diff UnitTestsSources/UnitTestsMain.cpp @ 73:ffa6dded91bd wasm

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 24 May 2017 11:59:24 +0200
parents c1cc3bdba18c
children f5f54ed8d307
line wrap: on
line diff
--- a/UnitTestsSources/UnitTestsMain.cpp	Wed May 24 10:36:41 2017 +0200
+++ b/UnitTestsSources/UnitTestsMain.cpp	Wed May 24 11:59:24 2017 +0200
@@ -22,15 +22,8 @@
 #include "gtest/gtest.h"
 
 #include "../Framework/Toolbox/OrthancAsynchronousWebService.h"
+#include "../Framework/Toolbox/OrthancSlicesLoader.h"
 #include "../Resources/Orthanc/Core/Logging.h"
-#include "../Framework/Toolbox/OrthancSynchronousWebService.h"
-#include "../Framework/Layers/OrthancFrameLayerSource.h"
-#include "../Framework/Widgets/LayerWidget.h"
-
-
-#include "../Resources/Orthanc/Core/Images/PngReader.h"
-#include "../Framework/Toolbox/MessagingToolbox.h"
-#include "../Framework/Toolbox/DicomFrameConverter.h"
 
 #include <boost/lexical_cast.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
@@ -38,766 +31,6 @@
 
 namespace OrthancStone
 {
-  class Slice
-  {
-  private:
-    enum Type
-    {
-      Type_Invalid,
-      Type_OrthancInstance
-      // TODO A slice could come from some DICOM file (URL)
-    };
-
-    Type                 type_;
-    std::string          orthancInstanceId_;
-    unsigned int         frame_;
-    SliceGeometry        geometry_;
-    double               pixelSpacingX_;
-    double               pixelSpacingY_;
-    double               thickness_;
-    unsigned int         width_;
-    unsigned int         height_;
-    DicomFrameConverter  converter_;
-      
-  public:
-    Slice() : type_(Type_Invalid)
-    {        
-    }
-
-    bool ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset,
-                           const std::string& instanceId,
-                           unsigned int frame)
-    {
-      OrthancPlugins::DicomDatasetReader reader(dataset);
-
-      unsigned int frameCount;
-      if (!reader.GetUnsignedIntegerValue(frameCount, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES))
-      {
-        frameCount = 1;   // Assume instance with one frame
-      }
-
-      if (frame >= frameCount)
-      {
-        return false;
-      }
-
-      if (!reader.GetDoubleValue(thickness_, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
-      {
-        thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
-      }
-
-      GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
-
-      std::string position, orientation;
-      if (dataset.GetStringValue(position, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) &&
-          dataset.GetStringValue(orientation, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
-      {
-        geometry_ = SliceGeometry(position, orientation);
-      }
-      
-      if (reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) &&
-          reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS))
-      {
-        orthancInstanceId_ = instanceId;
-        frame_ = frame;
-        converter_.ReadParameters(dataset);
-
-        type_ = Type_OrthancInstance;
-        return true;
-      }
-      else
-      {
-        return false;
-      }
-    }
-
-    bool IsOrthancInstance() const
-    {
-      return type_ == Type_OrthancInstance;
-    }
-
-    const std::string GetOrthancInstanceId() const
-    {
-      if (type_ != Type_OrthancInstance)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return orthancInstanceId_;
-    }
-
-    unsigned int GetFrame() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return frame_;
-    }
-
-    const SliceGeometry& GetGeometry() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return geometry_;
-    }
-
-    double GetThickness() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return thickness_;
-    }
-
-    double GetPixelSpacingX() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return pixelSpacingX_;
-    }
-
-    double GetPixelSpacingY() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return pixelSpacingY_;
-    }
-
-    unsigned int GetWidth() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return width_;
-    }
-
-    unsigned int GetHeight() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return height_;
-    }
-
-    const DicomFrameConverter& GetConverter() const
-    {
-      if (type_ == Type_Invalid)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-        
-      return converter_;
-    }
-  };
-
-
-  class SliceSorter : public boost::noncopyable
-  {
-  private:
-    class SliceWithDepth : public boost::noncopyable
-    {
-    private:
-      Slice   slice_;
-      double  depth_;
-
-    public:
-      SliceWithDepth(const Slice& slice) :
-        slice_(slice),
-        depth_(0)
-      {
-      }
-
-      void SetNormal(const Vector& normal)
-      {
-        depth_ = boost::numeric::ublas::inner_prod
-          (slice_.GetGeometry().GetOrigin(), normal);
-      }
-
-      double GetDepth() const
-      {
-        return depth_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-    struct Comparator
-    {
-      bool operator() (const SliceWithDepth* const& a,
-                       const SliceWithDepth* const& b) const
-      {
-        return a->GetDepth() < b->GetDepth();
-      }
-    };
-
-    typedef std::vector<SliceWithDepth*>  Slices;
-
-    Slices  slices_;
-    bool    hasNormal_;
-    
-  public:
-    SliceSorter() : hasNormal_(false)
-    {
-    }
-
-    ~SliceSorter()
-    {
-      for (size_t i = 0; i < slices_.size(); i++)
-      {
-        assert(slices_[i] != NULL);
-        delete slices_[i];
-      }
-    }
-    
-    void Reserve(size_t count)
-    {
-      slices_.reserve(count);
-    }
-
-    void AddSlice(const Slice& slice)
-    {
-      slices_.push_back(new SliceWithDepth(slice));
-    }
-
-    size_t GetSliceCount() const
-    {
-      return slices_.size();
-    }
-
-    const Slice& GetSlice(size_t i) const
-    {
-      if (i >= slices_.size())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-
-      assert(slices_[i] != NULL);
-      return slices_[i]->GetSlice();
-    }
-
-    void SetNormal(const Vector& normal)
-    {
-      for (size_t i = 0; i < slices_.size(); i++)
-      {
-        slices_[i]->SetNormal(normal);
-      }
-
-      hasNormal_ = true;
-    }
-    
-    void Sort()
-    {
-      if (!hasNormal_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-
-      Comparator comparator;
-      std::sort(slices_.begin(), slices_.end(), comparator);
-    }
-
-    void FilterNormal(const Vector& normal)
-    {
-      size_t pos = 0;
-
-      for (size_t i = 0; i < slices_.size(); i++)
-      {
-        if (GeometryToolbox::IsParallel(normal, slices_[i]->GetSlice().GetGeometry().GetNormal()))
-        {
-          // This slice is compatible with the selected normal
-          slices_[pos] = slices_[i];
-          pos += 1;
-        }
-        else
-        {
-          delete slices_[i];
-          slices_[i] = NULL;
-        }
-      }
-
-      slices_.resize(pos);
-    }
-    
-    bool SelectNormal(Vector& normal) const
-    {
-      std::vector<Vector>  normalCandidates;
-      std::vector<unsigned int>  normalCount;
-
-      bool found = false;
-
-      for (size_t i = 0; !found && i < GetSliceCount(); i++)
-      {
-        const Vector& normal = GetSlice(i).GetGeometry().GetNormal();
-
-        bool add = true;
-        for (size_t j = 0; add && j < normalCandidates.size(); j++)  // (*)
-        {
-          if (GeometryToolbox::IsParallel(normal, normalCandidates[j]))
-          {
-            normalCount[j] += 1;
-            add = false;
-          }
-        }
-
-        if (add)
-        {
-          if (normalCount.size() > 2)
-          {
-            // To get linear-time complexity in (*). This heuristics
-            // allows the series to have one single frame that is
-            // not parallel to the others (such a frame could be a
-            // generated preview)
-            found = false;
-          }
-          else
-          {
-            normalCandidates.push_back(normal);
-            normalCount.push_back(1);
-          }
-        }
-      }
-
-      for (size_t i = 0; !found && i < normalCandidates.size(); i++)
-      {
-        unsigned int count = normalCount[i];
-        if (count == GetSliceCount() ||
-            count + 1 == GetSliceCount())
-        {
-          normal = normalCandidates[i];
-          found = true;
-        }
-      }
-
-      return found;
-    }
-  };
-
-
-
-  class OrthancSlicesLoader : public boost::noncopyable
-  {
-  public:
-    class ICallback : public boost::noncopyable
-    {
-    public:
-      virtual ~ICallback()
-      {
-      }
-
-      virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader) = 0;
-
-      virtual void NotifyGeometryError(const OrthancSlicesLoader& loader) = 0;
-
-      virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader,
-                                         unsigned int sliceIndex,
-                                         const Slice& slice,
-                                         Orthanc::ImageAccessor* image) = 0;
-
-      virtual void NotifySliceImageError(const OrthancSlicesLoader& loader,
-                                         unsigned int sliceIndex,
-                                         const Slice& slice) = 0;
-    };
-    
-  private:
-    enum State
-    {
-      State_Error,
-      State_Initialization,
-      State_LoadingGeometry,
-      State_GeometryReady
-    };
-    
-    enum Mode
-    {
-      Mode_SeriesGeometry,
-      Mode_InstanceGeometry,
-      Mode_LoadImage
-    };
-
-    class Operation : public Orthanc::IDynamicObject
-    {
-    private:
-      Mode          mode_;
-      unsigned int  frame_;
-      unsigned int  sliceIndex_;
-      const Slice*  slice_;
-      std::string   instanceId_;
-
-      Operation(Mode mode) :
-        mode_(mode)
-      {
-      }
-
-    public:
-      Mode GetMode() const
-      {
-        return mode_;
-      }
-
-      unsigned int GetSliceIndex() const
-      {
-        assert(mode_ == Mode_LoadImage);
-        return sliceIndex_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        assert(mode_ == Mode_LoadImage && slice_ != NULL);
-        return *slice_;
-      }
-
-      unsigned int GetFrame() const
-      {
-        assert(mode_ == Mode_InstanceGeometry);
-        return frame_;
-      }
-      
-      const std::string& GetInstanceId() const
-      {
-        assert(mode_ == Mode_InstanceGeometry);
-        return instanceId_;
-      }
-      
-      static Operation* DownloadSeriesGeometry()
-      {
-        return new Operation(Mode_SeriesGeometry);
-      }
-
-      static Operation* DownloadInstanceGeometry(const std::string& instanceId,
-                                                 unsigned int frame)
-      {
-        std::auto_ptr<Operation> operation(new Operation(Mode_InstanceGeometry));
-        operation->instanceId_ = instanceId;
-        operation->frame_ = frame;
-        return operation.release();
-      }
-
-      static Operation* DownloadSliceImage(unsigned int  sliceIndex,
-                                           const Slice&  slice)
-      {
-        std::auto_ptr<Operation> tmp(new Operation(Mode_LoadImage));
-        tmp->sliceIndex_ = sliceIndex;
-        tmp->slice_ = &slice;
-        return tmp.release();
-      }
-    };
-    
-
-    class WebCallback : public IWebService::ICallback
-    {
-    private:
-      OrthancSlicesLoader&  that_;
-
-    public:
-      WebCallback(OrthancSlicesLoader&  that) :
-        that_(that)
-      {
-      }
-
-      virtual void NotifySuccess(const std::string& uri,
-                                 const void* answer,
-                                 size_t answerSize,
-                                 Orthanc::IDynamicObject* payload)
-      {
-        std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload));
-
-        switch (operation->GetMode())
-        {
-          case Mode_SeriesGeometry:
-            that_.ParseSeriesGeometry(answer, answerSize);
-            break;
-
-          case Mode_InstanceGeometry:
-            that_.ParseInstanceGeometry(operation->GetInstanceId(),
-                                        operation->GetFrame(), answer, answerSize);
-            break;
-
-          case Mode_LoadImage:
-            that_.ParseSliceImage(*operation, answer, answerSize);
-            break;
-
-          default:
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-        }
-      }
-
-      virtual void NotifyError(const std::string& uri,
-                               Orthanc::IDynamicObject* payload)
-      {
-        std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload));
-        LOG(ERROR) << "Cannot download " << uri;
-
-        switch (operation->GetMode())
-        {
-          case Mode_SeriesGeometry:
-            that_.userCallback_.NotifyGeometryError(that_);
-            that_.state_ = State_Error;
-            break;
-
-          case Mode_LoadImage:
-            that_.userCallback_.NotifySliceImageError(that_, operation->GetSliceIndex(),
-                                                      operation->GetSlice());
-            break;
-          
-          default:
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-        }
-      }     
-    };
-
-
-    WebCallback   webCallback_;
-    ICallback&    userCallback_;
-    IWebService&  orthanc_;
-    State         state_;
-    SliceSorter   slices_;
-
-
-    void ParseSeriesGeometry(const void* answer,
-                             size_t size)
-    {
-      Json::Value series;
-      if (!MessagingToolbox::ParseJson(series, answer, size) ||
-          series.type() != Json::objectValue)
-      {
-        userCallback_.NotifyGeometryError(*this);
-        return;
-      }
-
-      Json::Value::Members instances = series.getMemberNames();
-
-      slices_.Reserve(instances.size());
-
-      for (size_t i = 0; i < instances.size(); i++)
-      {
-        OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]);
-
-        Slice slice;
-        if (slice.ParseOrthancFrame(dataset, instances[i], 0 /* todo */))
-        {
-          slices_.AddSlice(slice);
-        }
-        else
-        {
-          LOG(WARNING) << "Skipping invalid instance " << instances[i];
-        }
-      }
-
-      bool ok = false;
-      
-      if (slices_.GetSliceCount() > 0)
-      {
-        Vector normal;
-        if (slices_.SelectNormal(normal))
-        {
-          slices_.FilterNormal(normal);
-          slices_.SetNormal(normal);
-          slices_.Sort();
-          ok = true;
-        }
-      }
-
-      state_ = State_GeometryReady;
-
-      if (ok)
-      {
-        LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)";
-        userCallback_.NotifyGeometryReady(*this);
-      }
-      else
-      {
-        LOG(ERROR) << "This series is empty";
-        userCallback_.NotifyGeometryError(*this);
-      }
-    }
-
-
-    void ParseInstanceGeometry(const std::string& instanceId,
-                               unsigned int frame,
-                               const void* answer,
-                               size_t size)
-    {
-      Json::Value tags;
-      if (!MessagingToolbox::ParseJson(tags, answer, size) ||
-          tags.type() != Json::objectValue)
-      {
-        userCallback_.NotifyGeometryError(*this);
-        return;
-      }
-
-      OrthancPlugins::FullOrthancDataset dataset(tags);
-
-      state_ = State_GeometryReady;
-      
-      Slice slice;
-      if (slice.ParseOrthancFrame(dataset, instanceId, frame))
-      {
-        LOG(INFO) << "Loaded instance " << instanceId;
-        slices_.AddSlice(slice);
-        userCallback_.NotifyGeometryReady(*this);
-      }
-      else
-      {
-        LOG(WARNING) << "Skipping invalid instance " << instanceId;
-        userCallback_.NotifyGeometryError(*this);
-      }
-    }
-
-
-    void ParseSliceImage(const Operation& operation,
-                         const void* answer,
-                         size_t size)
-    {
-      std::auto_ptr<Orthanc::PngReader>  image(new Orthanc::PngReader);
-      image->ReadFromMemory(answer, size);
-
-      bool ok = (image->GetWidth() == operation.GetSlice().GetWidth() ||
-                 image->GetHeight() == operation.GetSlice().GetHeight());
-      
-      if (ok &&
-          operation.GetSlice().GetConverter().GetExpectedPixelFormat() ==
-          Orthanc::PixelFormat_SignedGrayscale16)
-      {
-        if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
-        {
-          image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
-        }
-        else
-        {
-          ok = false;
-        }
-      }
-
-      if (ok)
-      {
-        userCallback_.NotifySliceImageReady(*this, operation.GetSliceIndex(),
-                                        operation.GetSlice(), image.release());
-      }
-      else
-      {
-        userCallback_.NotifySliceImageError(*this, operation.GetSliceIndex(),
-                                        operation.GetSlice());
-      }
-    }
-    
-    
-  public:
-    OrthancSlicesLoader(ICallback& callback,
-                 IWebService& orthanc) :
-      webCallback_(*this),
-      userCallback_(callback),
-      orthanc_(orthanc),
-      state_(State_Initialization)
-    {
-    }
-
-    void ScheduleLoadSeries(const std::string& seriesId)
-    {
-      if (state_ != State_Initialization)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        state_ = State_LoadingGeometry;
-        std::string uri = "/series/" + seriesId + "/instances-tags";
-        orthanc_.ScheduleGetRequest(webCallback_, uri, Operation::DownloadSeriesGeometry());
-      }
-    }
-
-    void ScheduleLoadInstance(const std::string& instanceId,
-                              unsigned int frame)
-    {
-      if (state_ != State_Initialization)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        state_ = State_LoadingGeometry;
-        std::string uri = "/instances/" + instanceId + "/tags";
-        orthanc_.ScheduleGetRequest
-          (webCallback_, uri, Operation::DownloadInstanceGeometry(instanceId, frame));
-      }
-    }
-
-    size_t GetSliceCount() const
-    {
-      if (state_ != State_GeometryReady)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-
-      return slices_.GetSliceCount();
-    }
-
-    const Slice& GetSlice(size_t index) const
-    {
-      if (state_ != State_GeometryReady)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-
-      return slices_.GetSlice(index);
-    }
-
-    void ScheduleLoadSliceImage(size_t index)
-    {
-      if (state_ != State_GeometryReady)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        const Slice& slice = GetSlice(index);
-
-        std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + 
-                           boost::lexical_cast<std::string>(slice.GetFrame()));
-
-        switch (slice.GetConverter().GetExpectedPixelFormat())
-        {
-          case Orthanc::PixelFormat_RGB24:
-            uri += "/preview";
-            break;
-
-          case Orthanc::PixelFormat_Grayscale16:
-            uri += "/image-uint16";
-            break;
-
-          case Orthanc::PixelFormat_SignedGrayscale16:
-            uri += "/image-int16";
-            break;
-
-          default:
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        orthanc_.ScheduleGetRequest(webCallback_, uri, Operation::DownloadSliceImage(index, slice));
-      }
-    }
-  };
-
-
   class Tata : public OrthancSlicesLoader::ICallback
   {
   public: