changeset 937:86ac61a040c9

Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 31 Jul 2019 10:24:09 +0200
parents 775ebd43bd3b
children eaaa9b574e05
files Applications/Generic/GuiAdapter.cpp Applications/Generic/GuiAdapter.h Framework/Loaders/DicomStructureSetLoader.cpp Framework/Loaders/DicomStructureSetLoader.h Framework/Loaders/LoaderCache.cpp Framework/Loaders/LoaderCache.h Framework/Loaders/OrthancMultiframeVolumeLoader.cpp Framework/Loaders/OrthancMultiframeVolumeLoader.h Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h
diffstat 10 files changed, 94 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Generic/GuiAdapter.cpp	Mon Jul 29 15:39:45 2019 +0200
+++ b/Applications/Generic/GuiAdapter.cpp	Wed Jul 31 10:24:09 2019 +0200
@@ -51,7 +51,7 @@
   }
 
 #if ORTHANC_ENABLE_WASM == 1
-  void GuiAdapter::Run()
+  void GuiAdapter::Run(GuiAdapterRunFunc /*func*/, void* /*cookie*/)
   {
   }
 
@@ -723,7 +723,7 @@
 # endif
 
   // SDL ONLY
-  void GuiAdapter::Run()
+  void GuiAdapter::Run(GuiAdapterRunFunc func, void* cookie)
   {
 #if 1
     // TODO: MAKE THIS DYNAMIC !!! See SdlOpenGLViewport vs Cairo in ViewportWrapper
@@ -741,6 +741,8 @@
     {
       {
         LockingEmitter::WriterLock lock(lockingEmitter_);
+        if(func != NULL)
+          (*func)(cookie);
         OnAnimationFrame(); // in SDL we must call it
       }
 
--- a/Applications/Generic/GuiAdapter.h	Mon Jul 29 15:39:45 2019 +0200
+++ b/Applications/Generic/GuiAdapter.h	Wed Jul 31 10:24:09 2019 +0200
@@ -218,6 +218,8 @@
 
 #endif
 
+  typedef void (*GuiAdapterRunFunc)(void*);
+
   class GuiAdapter
   {
   public:
@@ -276,7 +278,7 @@
     Under wasm, it returns without doing anything, since the event loop is managed
     by the browser.
     */
-    void Run();
+    void Run(GuiAdapterRunFunc func = NULL, void* cookie = NULL);
 
 #if ORTHANC_ENABLE_WASM != 1
     /**
--- a/Framework/Loaders/DicomStructureSetLoader.cpp	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/DicomStructureSetLoader.cpp	Wed Jul 31 10:24:09 2019 +0200
@@ -58,6 +58,7 @@
         // All the referenced instances have been loaded, finalize the RT-STRUCT
         loader.content_->CheckReferencedSlices();
         loader.revision_++;
+        loader.SetStructuresReady();
       }
     }
   };
@@ -225,10 +226,12 @@
 
   DicomStructureSetLoader::DicomStructureSetLoader(IOracle& oracle,
                                                    IObservable& oracleObservable) :
+    IObservable(oracleObservable.GetBroker()),
     LoaderStateMachine(oracle, oracleObservable),
     revision_(0),
     countProcessedInstances_(0),
-    countReferencedInstances_(0)
+    countReferencedInstances_(0),
+    structuresReady_(false)
   {
   }
     
@@ -266,4 +269,17 @@
       return new Slice(*content_, revision_, cuttingPlane);
     }
   }
+
+  void DicomStructureSetLoader::SetStructuresReady()
+  {
+    ORTHANC_ASSERT(!structuresReady_);
+    structuresReady_ = true;
+    BroadcastMessage(DicomStructureSetLoader::StructuresReady(*this));
+  }
+
+  bool DicomStructureSetLoader::AreStructuresReady() const
+  {
+    return structuresReady_;
+  }
+
 }
--- a/Framework/Loaders/DicomStructureSetLoader.h	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/DicomStructureSetLoader.h	Wed Jul 31 10:24:09 2019 +0200
@@ -29,7 +29,8 @@
 {
   class DicomStructureSetLoader :
     public LoaderStateMachine,
-    public IVolumeSlicer
+    public IVolumeSlicer,
+    public IObservable
   {
   private:
     class Slice;
@@ -44,8 +45,13 @@
     std::string                       instanceId_;
     unsigned int                      countProcessedInstances_;
     unsigned int                      countReferencedInstances_;  
+
+    // will be set to true once the loading is finished
+    bool                              structuresReady_;
     
   public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, StructuresReady, DicomStructureSetLoader);
+
     DicomStructureSetLoader(IOracle& oracle,
                             IObservable& oracleObservable);    
     
@@ -54,5 +60,9 @@
     void LoadInstance(const std::string& instanceId);
 
     virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane);
+
+    void SetStructuresReady();
+
+    bool AreStructuresReady() const;
   };
 }
--- a/Framework/Loaders/LoaderCache.cpp	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/LoaderCache.cpp	Wed Jul 31 10:24:09 2019 +0200
@@ -119,6 +119,18 @@
     }
   }
 
+  boost::shared_ptr<OrthancMultiframeVolumeLoader> LoaderCache::GetMultiframeVolumeLoader(std::string instanceUuid)
+  {
+    // if the loader is not available, let's trigger its creation
+    if(multiframeVolumeLoaders_.find(instanceUuid) == multiframeVolumeLoaders_.end())
+    {
+      GetMultiframeDicomVolumeImageMPRSlicer(instanceUuid);
+    }
+    ORTHANC_ASSERT(multiframeVolumeLoaders_.find(instanceUuid) != multiframeVolumeLoaders_.end());
+
+    return multiframeVolumeLoaders_[instanceUuid];
+  }
+
   boost::shared_ptr<DicomVolumeImageMPRSlicer> LoaderCache::GetMultiframeDicomVolumeImageMPRSlicer(std::string instanceUuid)
   {
     try
--- a/Framework/Loaders/LoaderCache.h	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/LoaderCache.h	Wed Jul 31 10:24:09 2019 +0200
@@ -50,8 +50,13 @@
 
     boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader>
       GetSeriesVolumeProgressiveLoader      (std::string seriesUuid);
+    
     boost::shared_ptr<DicomVolumeImageMPRSlicer>
       GetMultiframeDicomVolumeImageMPRSlicer(std::string instanceUuid);
+
+    boost::shared_ptr<OrthancMultiframeVolumeLoader>
+      GetMultiframeVolumeLoader(std::string instanceUuid);
+
     boost::shared_ptr<DicomStructureSetLoader>
       GetDicomStructureSetLoader            (std::string instanceUuid);
 
--- a/Framework/Loaders/OrthancMultiframeVolumeLoader.cpp	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/OrthancMultiframeVolumeLoader.cpp	Wed Jul 31 10:24:09 2019 +0200
@@ -316,6 +316,7 @@
 
     volume_->IncrementRevision();
 
+    pixelDataLoaded_ = true;
     BroadcastMessage(DicomVolumeImage::ContentUpdatedMessage(*volume_));
   }
 
@@ -325,7 +326,8 @@
                                                                IObservable& oracleObservable) :
     LoaderStateMachine(oracle, oracleObservable),
     IObservable(oracleObservable.GetBroker()),
-    volume_(volume)
+    volume_(volume),
+    pixelDataLoaded_(false)
   {
     if (volume.get() == NULL)
     {
--- a/Framework/Loaders/OrthancMultiframeVolumeLoader.h	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/OrthancMultiframeVolumeLoader.h	Wed Jul 31 10:24:09 2019 +0200
@@ -41,6 +41,7 @@
     boost::shared_ptr<DicomVolumeImage>  volume_;
     std::string                          instanceId_;
     std::string                          transferSyntaxUid_;
+    bool                                 pixelDataLoaded_;
 
     const std::string& GetInstanceId() const;
 
@@ -62,6 +63,11 @@
     
     virtual ~OrthancMultiframeVolumeLoader();
 
+    bool IsPixelDataLoaded() const
+    {
+      return pixelDataLoaded_;
+    }
+
     void LoadInstance(const std::string& instanceId);
   };
 }
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Jul 31 10:24:09 2019 +0200
@@ -264,10 +264,14 @@
       if (quality == BEST_QUALITY)
       {
         std::auto_ptr<GetOrthancImageCommand> tmp(new GetOrthancImageCommand);
-        // TODO: review the following comment. Commented out by bgo on 2019-07-19
-        // reason: Alain has seen cases where gzipping the uint16 image took 11 sec 
-        // to produce 5mb. The unzipped request was much much faster.
-        //tmp->SetHttpHeader("Accept-Encoding", "gzip");
+        // TODO: review the following comment. 
+        // - Commented out by bgo on 2019-07-19 | reason: Alain has seen cases 
+        //   where gzipping the uint16 image took 11 sec to produce 5mb. 
+        //   The unzipped request was much much faster.
+        // - Re-enabled on 2019-07-30. Reason: in Web Assembly, the browser 
+        //   does not use the Accept-Encoding header and always requests
+        //   compression. Furthermore, NOT 
+        tmp->SetHttpHeader("Accept-Encoding", "gzip");
         tmp->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
         tmp->SetInstanceUri(instance, slice.GetExpectedPixelFormat());
         tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
@@ -288,6 +292,12 @@
       command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex));
       oracle_.Schedule(*this, command.release());
     }
+    else
+    {
+      // loading is finished!
+      volumeImageReadyInHighQuality_ = true;
+      BroadcastMessage(OrthancSeriesVolumeProgressiveLoader::VolumeImageReadyInHighQuality(*this));
+    }
   }
 
 /**
@@ -415,7 +425,8 @@
     active_(false),
     simultaneousDownloads_(4),
     volume_(volume),
-    sorter_(new BasicFetchingItemsSorter::Factory)
+    sorter_(new BasicFetchingItemsSorter::Factory),
+    volumeImageReadyInHighQuality_(false)
   {
     oracleObservable.RegisterObserverCallback(
       new Callable<OrthancSeriesVolumeProgressiveLoader, OrthancRestApiCommand::SuccessMessage>
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Mon Jul 29 15:39:45 2019 +0200
+++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Wed Jul 31 10:24:09 2019 +0200
@@ -104,17 +104,21 @@
 
     void LoadJpegSliceContent(const GetOrthancWebViewerJpegCommand::SuccessMessage& message);
 
-    IOracle&                                       oracle_;
-    bool                                           active_;
-    unsigned int                                   simultaneousDownloads_;
-    SeriesGeometry                                 seriesGeometry_;
-    boost::shared_ptr<DicomVolumeImage>            volume_;
-    std::auto_ptr<IFetchingItemsSorter::IFactory>  sorter_;
-    std::auto_ptr<IFetchingStrategy>               strategy_;
-    std::vector<unsigned int>                      slicesQuality_;
+    IOracle&                                      oracle_;
+    bool                                          active_;
+    unsigned int                                  simultaneousDownloads_;
+    SeriesGeometry                                seriesGeometry_;
+    boost::shared_ptr<DicomVolumeImage>           volume_;
+    std::auto_ptr<IFetchingItemsSorter::IFactory> sorter_;
+    std::auto_ptr<IFetchingStrategy>              strategy_;
+    std::vector<unsigned int>                     slicesQuality_;
+    bool                                          volumeImageReadyInHighQuality_;
 
 
   public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeImageReadyInHighQuality, OrthancSeriesVolumeProgressiveLoader);
+
+
     OrthancSeriesVolumeProgressiveLoader(const boost::shared_ptr<DicomVolumeImage>& volume,
                                          IOracle& oracle,
                                          IObservable& oracleObservable);
@@ -123,6 +127,11 @@
 
     void SetSimultaneousDownloads(unsigned int count);
 
+    bool IsVolumeImageReadyInHighQuality() const
+    {
+      return volumeImageReadyInHighQuality_;
+    }
+
     void LoadSeries(const std::string& seriesId);
 
     /**