changeset 396:ed7146fa2c98

rename ILayerSource as IVolumeSlicer, and OrthancFrameLayerSource as as DicomSeriesVolumeSlicer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 10 Nov 2018 09:29:08 +0100
parents 5f13809f3f76
children 1d9dd542adfe
files Applications/Samples/SimpleViewer/SimpleViewerApplication.h Applications/Samples/SimpleViewerApplicationSingleFile.h Applications/Samples/SingleFrameApplication.h Framework/Layers/DicomSeriesVolumeSlicer.cpp Framework/Layers/DicomSeriesVolumeSlicer.h Framework/Layers/DicomStructureSetRendererFactory.h Framework/Layers/ILayerSource.h Framework/Layers/IVolumeSlicer.h Framework/Layers/LayerSourceBase.cpp Framework/Layers/LayerSourceBase.h Framework/Layers/OrthancFrameLayerSource.cpp Framework/Layers/OrthancFrameLayerSource.h Framework/Layers/VolumeSlicerBase.cpp Framework/Layers/VolumeSlicerBase.h Framework/SmartLoader.cpp Framework/SmartLoader.h Framework/StoneEnumerations.h Framework/Widgets/SliceViewerWidget.cpp Framework/Widgets/SliceViewerWidget.h Framework/dev.h Resources/CMake/OrthancStoneConfiguration.cmake UnitTestsSources/UnitTestsMain.cpp
diffstat 22 files changed, 616 insertions(+), 619 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Sat Nov 10 09:29:08 2018 +0100
@@ -23,7 +23,6 @@
 
 #include "Applications/IStoneApplication.h"
 
-#include "Framework/Layers/OrthancFrameLayerSource.h"
 #include "Framework/Layers/CircleMeasureTracker.h"
 #include "Framework/Layers/LineMeasureTracker.h"
 #include "Framework/Widgets/SliceViewerWidget.h"
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Sat Nov 10 09:29:08 2018 +0100
@@ -23,7 +23,6 @@
 
 #include "SampleApplicationBase.h"
 
-#include "../../Framework/Layers/OrthancFrameLayerSource.h"
 #include "../../Framework/Layers/CircleMeasureTracker.h"
 #include "../../Framework/Layers/LineMeasureTracker.h"
 #include "../../Framework/Widgets/SliceViewerWidget.h"
--- a/Applications/Samples/SingleFrameApplication.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Applications/Samples/SingleFrameApplication.h	Sat Nov 10 09:29:08 2018 +0100
@@ -23,7 +23,7 @@
 
 #include "SampleApplicationBase.h"
 
-#include "../../Framework/Layers/OrthancFrameLayerSource.h"
+#include "../../Framework/Layers/DicomSeriesVolumeSlicer.h"
 #include "../../Framework/Widgets/SliceViewerWidget.h"
 
 #include <Core/Logging.h>
@@ -182,7 +182,7 @@
       }
         
       
-      void OnMainWidgetGeometryReady(const ILayerSource::GeometryReadyMessage& message)
+      void OnMainWidgetGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
       {
         // Once the geometry of the series is downloaded from Orthanc,
         // display its middle slice, and adapt the viewport to fit this
@@ -197,7 +197,7 @@
       
       std::auto_ptr<Interactor>         mainWidgetInteractor_;
       std::auto_ptr<OrthancApiClient>   orthancApiClient_;
-      const OrthancFrameLayerSource*    source_;
+      const DicomSeriesVolumeSlicer*    source_;
       unsigned int                      slice_;
 
     public:
@@ -245,10 +245,10 @@
         orthancApiClient_.reset(new OrthancApiClient(GetBroker(), context_->GetWebService()));
         mainWidget_ = new SliceViewerWidget(GetBroker(), "main-widget");
 
-        std::auto_ptr<OrthancFrameLayerSource> layer(new OrthancFrameLayerSource(GetBroker(), *orthancApiClient_));
+        std::auto_ptr<DicomSeriesVolumeSlicer> layer(new DicomSeriesVolumeSlicer(GetBroker(), *orthancApiClient_));
         source_ = layer.get();
         layer->LoadFrame(instance, frame);
-        layer->RegisterObserverCallback(new Callable<SingleFrameApplication, ILayerSource::GeometryReadyMessage>(*this, &SingleFrameApplication::OnMainWidgetGeometryReady));
+        layer->RegisterObserverCallback(new Callable<SingleFrameApplication, IVolumeSlicer::GeometryReadyMessage>(*this, &SingleFrameApplication::OnMainWidgetGeometryReady));
         GetMainWidget().AddLayer(layer.release());
 
         RenderStyle s;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Layers/DicomSeriesVolumeSlicer.cpp	Sat Nov 10 09:29:08 2018 +0100
@@ -0,0 +1,150 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "DicomSeriesVolumeSlicer.h"
+
+#include "FrameRenderer.h"
+#include "../Toolbox/DicomFrameConverter.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancStone
+{
+
+  void DicomSeriesVolumeSlicer::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
+  {
+    if (message.GetOrigin().GetSliceCount() > 0)
+    {
+      VolumeSlicerBase::NotifyGeometryReady();
+    }
+    else
+    {
+      VolumeSlicerBase::NotifyGeometryError();
+    }
+  }
+
+  void DicomSeriesVolumeSlicer::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
+  {
+    VolumeSlicerBase::NotifyGeometryError();
+  }
+
+
+  class DicomSeriesVolumeSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory
+  {
+  private:
+    const OrthancSlicesLoader::SliceImageReadyMessage&  message_;
+
+  public:
+    RendererFactory(const OrthancSlicesLoader::SliceImageReadyMessage& message) :
+      message_(message)
+    {
+    }
+
+    virtual ILayerRenderer* CreateRenderer() const
+    {
+      bool isFull = (message_.GetEffectiveQuality() == SliceImageQuality_FullPng ||
+                     message_.GetEffectiveQuality() == SliceImageQuality_FullPam);
+
+      return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull);
+    }
+  };
+
+  void DicomSeriesVolumeSlicer::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
+  {
+    // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache)
+    EmitMessage(FrameReadyMessage(*this, message.GetImage(), 
+                                  message.GetEffectiveQuality(), message.GetSlice()));
+
+    // then notify that the layer is ready for render
+    RendererFactory factory(message);
+    VolumeSlicerBase::NotifyLayerReady(factory, message.GetSlice().GetGeometry());
+  }
+
+  void DicomSeriesVolumeSlicer::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
+  {
+    VolumeSlicerBase::NotifyLayerError(message.GetSlice().GetGeometry());
+  }
+
+
+  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(MessageBroker& broker, OrthancApiClient& orthanc) :
+    VolumeSlicerBase(broker),
+    IObserver(broker),
+    loader_(broker, orthanc),
+    quality_(SliceImageQuality_FullPng)
+  {
+    loader_.RegisterObserverCallback(new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage>(*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady));
+    loader_.RegisterObserverCallback(new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage>(*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError));
+    loader_.RegisterObserverCallback(new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage>(*this, &DicomSeriesVolumeSlicer::OnSliceImageReady));
+    loader_.RegisterObserverCallback(new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage>(*this, &DicomSeriesVolumeSlicer::OnSliceImageError));
+  }
+
+  
+  void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId)
+  {
+    loader_.ScheduleLoadSeries(seriesId);
+  }
+
+
+  void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId)
+  {
+    loader_.ScheduleLoadInstance(instanceId);
+  }
+
+
+  void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId,
+                                          unsigned int frame)
+  {
+    loader_.ScheduleLoadFrame(instanceId, frame);
+  }
+
+
+  bool DicomSeriesVolumeSlicer::GetExtent(std::vector<Vector>& points,
+                                          const CoordinateSystem3D& viewportSlice)
+  {
+    size_t index;
+
+    if (loader_.IsGeometryReady() &&
+        loader_.LookupSlice(index, viewportSlice))
+    {
+      loader_.GetSlice(index).GetExtent(points);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  
+  void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice)
+  {
+    size_t index;
+
+    if (loader_.IsGeometryReady() &&
+        loader_.LookupSlice(index, viewportSlice))
+    {
+      loader_.ScheduleLoadSliceImage(index, quality_);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Layers/DicomSeriesVolumeSlicer.h	Sat Nov 10 09:29:08 2018 +0100
@@ -0,0 +1,124 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "VolumeSlicerBase.h"
+#include "../Toolbox/IWebService.h"
+#include "../Toolbox/OrthancSlicesLoader.h"
+#include "../Toolbox/OrthancApiClient.h"
+
+namespace OrthancStone
+{  
+  // this class is in charge of loading a Frame.
+  // once it's been loaded (first the geometry and then the image),
+  // messages are sent to observers so they can use it
+  class DicomSeriesVolumeSlicer :
+    public VolumeSlicerBase,
+    public IObserver
+    //private OrthancSlicesLoader::ISliceLoaderObserver
+  {
+  public:
+    // TODO: Add "frame" and "instanceId"
+    class FrameReadyMessage : public OriginMessage<MessageType_DicomSeriesVolumeSlicer_FrameReady, DicomSeriesVolumeSlicer>
+    {
+    private:
+      const Orthanc::ImageAccessor&  frame_;
+      SliceImageQuality              imageQuality_;
+      const Slice&                   slice_;
+
+    public:
+      FrameReadyMessage(DicomSeriesVolumeSlicer& origin,
+                        const Orthanc::ImageAccessor& frame,
+                        SliceImageQuality imageQuality,
+                        const Slice& slice) :
+        OriginMessage(origin),
+        frame_(frame),
+        imageQuality_(imageQuality),
+        slice_(slice)
+      {
+      }
+
+      const Orthanc::ImageAccessor& GetFrame() const
+      {
+        return frame_;
+      }
+
+      SliceImageQuality GetImageQuality() const
+      {
+        return imageQuality_;
+      }
+
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+    
+  private:
+    class RendererFactory;
+    
+    OrthancSlicesLoader  loader_;
+    SliceImageQuality    quality_;
+
+  public:
+    DicomSeriesVolumeSlicer(MessageBroker& broker, OrthancApiClient& orthanc);
+
+    void LoadSeries(const std::string& seriesId);
+
+    void LoadInstance(const std::string& instanceId);
+
+    void LoadFrame(const std::string& instanceId,
+                   unsigned int frame);
+
+    void SetImageQuality(SliceImageQuality quality)
+    {
+      quality_ = quality;
+    }
+
+    SliceImageQuality GetImageQuality() const
+    {
+      return quality_;
+    }
+
+    size_t GetSliceCount() const
+    {
+      return loader_.GetSliceCount();
+    }
+
+    const Slice& GetSlice(size_t slice) const 
+    {
+      return loader_.GetSlice(slice);
+    }
+
+    virtual bool GetExtent(std::vector<Vector>& points,
+                           const CoordinateSystem3D& viewportSlice);
+
+    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice);
+
+protected:
+    void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message);
+    void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message);
+    void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message);
+    void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message);
+  };
+}
--- a/Framework/Layers/DicomStructureSetRendererFactory.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/Layers/DicomStructureSetRendererFactory.h	Sat Nov 10 09:29:08 2018 +0100
@@ -21,13 +21,13 @@
 
 #pragma once
 
-#include "LayerSourceBase.h"
+#include "VolumeSlicerBase.h"
 #include "../Volumes/StructureSetLoader.h"
 
 namespace OrthancStone
 {
   class DicomStructureSetRendererFactory :
-    public LayerSourceBase,
+    public VolumeSlicerBase,
     private IVolumeLoader::IObserver
   {
   private:
@@ -36,24 +36,24 @@
 
     virtual void NotifyGeometryReady(const IVolumeLoader& loader)
     {
-      LayerSourceBase::NotifyGeometryReady();
+      VolumeSlicerBase::NotifyGeometryReady();
     }
 
     virtual void NotifyGeometryError(const IVolumeLoader& loader)
     {
-      LayerSourceBase::NotifyGeometryError();
+      VolumeSlicerBase::NotifyGeometryError();
     }
 
     virtual void NotifyContentChange(const IVolumeLoader& loader)
     {
-      LayerSourceBase::NotifyContentChange();
+      VolumeSlicerBase::NotifyContentChange();
     }
 
     StructureSetLoader& loader_;
 
   public:
     DicomStructureSetRendererFactory(MessageBroker& broker, StructureSetLoader& loader) :
-      LayerSourceBase(broker),
+      VolumeSlicerBase(broker),
       loader_(loader)
     {
       loader_.Register(*this);
--- a/Framework/Layers/ILayerSource.h	Sat Nov 10 09:14:12 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "ILayerRenderer.h"
-#include "../Toolbox/Slice.h"
-#include "../../Framework/Messages/IObservable.h"
-#include "../../Framework/Messages/IMessage.h"
-#include "Core/Images/Image.h"
-#include <boost/shared_ptr.hpp>
-
-namespace OrthancStone
-{
-  class ILayerSource : public IObservable
-  {
-  public:
-    typedef OriginMessage<MessageType_LayerSource_GeometryReady, ILayerSource>  GeometryReadyMessage;
-    typedef OriginMessage<MessageType_LayerSource_GeometryError, ILayerSource>  GeometryErrorMessage;
-    typedef OriginMessage<MessageType_LayerSource_ContentChanged, ILayerSource> ContentChangedMessage;
-
-    class SliceChangedMessage : public OriginMessage<MessageType_LayerSource_SliceChanged, ILayerSource>
-    {
-    private:
-      const Slice& slice_;
-
-    public:
-      SliceChangedMessage(ILayerSource& origin,
-                          const Slice& slice) :
-        OriginMessage(origin),
-        slice_(slice)
-      {
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-    
-
-    class LayerReadyMessage : public OriginMessage<MessageType_LayerSource_LayerReady, ILayerSource>
-    {
-    public:
-      class IRendererFactory : public boost::noncopyable
-      {
-      public:
-        virtual ~IRendererFactory()
-        {
-        }
-
-        virtual ILayerRenderer* CreateRenderer() const = 0;
-      };
-    
-    private:
-      const IRendererFactory&    factory_;
-      const CoordinateSystem3D&  slice_;
-
-    public:
-      LayerReadyMessage(ILayerSource& origin,
-                        const IRendererFactory& rendererFactory,
-                        const CoordinateSystem3D& slice) :
-        OriginMessage(origin),
-        factory_(rendererFactory),
-        slice_(slice)
-      {
-      }
-
-      ILayerRenderer* CreateRenderer() const
-      {
-        return factory_.CreateRenderer();
-      }
-
-      const CoordinateSystem3D& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-
-    class LayerErrorMessage : public OriginMessage<MessageType_LayerSource_LayerError, ILayerSource>
-    {
-    private:
-      const CoordinateSystem3D&  slice_;
-
-    public:
-      LayerErrorMessage(ILayerSource& origin,
-                        const CoordinateSystem3D& slice) :
-        OriginMessage(origin),
-        slice_(slice)
-      {
-      }
-
-      const CoordinateSystem3D& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-
-    ILayerSource(MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
-    virtual ~ILayerSource()
-    {
-    }
-
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice) = 0;
-
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) = 0;
-  };
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Layers/IVolumeSlicer.h	Sat Nov 10 09:29:08 2018 +0100
@@ -0,0 +1,133 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "ILayerRenderer.h"
+#include "../Toolbox/Slice.h"
+#include "../../Framework/Messages/IObservable.h"
+#include "../../Framework/Messages/IMessage.h"
+#include "Core/Images/Image.h"
+#include <boost/shared_ptr.hpp>
+
+namespace OrthancStone
+{
+  class IVolumeSlicer : public IObservable
+  {
+  public:
+    typedef OriginMessage<MessageType_LayerSource_GeometryReady, IVolumeSlicer>  GeometryReadyMessage;
+    typedef OriginMessage<MessageType_LayerSource_GeometryError, IVolumeSlicer>  GeometryErrorMessage;
+    typedef OriginMessage<MessageType_LayerSource_ContentChanged, IVolumeSlicer> ContentChangedMessage;
+
+    class SliceChangedMessage : public OriginMessage<MessageType_LayerSource_SliceChanged, IVolumeSlicer>
+    {
+    private:
+      const Slice& slice_;
+
+    public:
+      SliceChangedMessage(IVolumeSlicer& origin,
+                          const Slice& slice) :
+        OriginMessage(origin),
+        slice_(slice)
+      {
+      }
+
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+    
+
+    class LayerReadyMessage : public OriginMessage<MessageType_LayerSource_LayerReady, IVolumeSlicer>
+    {
+    public:
+      class IRendererFactory : public boost::noncopyable
+      {
+      public:
+        virtual ~IRendererFactory()
+        {
+        }
+
+        virtual ILayerRenderer* CreateRenderer() const = 0;
+      };
+    
+    private:
+      const IRendererFactory&    factory_;
+      const CoordinateSystem3D&  slice_;
+
+    public:
+      LayerReadyMessage(IVolumeSlicer& origin,
+                        const IRendererFactory& rendererFactory,
+                        const CoordinateSystem3D& slice) :
+        OriginMessage(origin),
+        factory_(rendererFactory),
+        slice_(slice)
+      {
+      }
+
+      ILayerRenderer* CreateRenderer() const
+      {
+        return factory_.CreateRenderer();
+      }
+
+      const CoordinateSystem3D& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+
+    class LayerErrorMessage : public OriginMessage<MessageType_LayerSource_LayerError, IVolumeSlicer>
+    {
+    private:
+      const CoordinateSystem3D&  slice_;
+
+    public:
+      LayerErrorMessage(IVolumeSlicer& origin,
+                        const CoordinateSystem3D& slice) :
+        OriginMessage(origin),
+        slice_(slice)
+      {
+      }
+
+      const CoordinateSystem3D& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+
+    IVolumeSlicer(MessageBroker& broker) :
+      IObservable(broker)
+    {
+    }
+    
+    virtual ~IVolumeSlicer()
+    {
+    }
+
+    virtual bool GetExtent(std::vector<Vector>& points,
+                           const CoordinateSystem3D& viewportSlice) = 0;
+
+    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) = 0;
+  };
+}
--- a/Framework/Layers/LayerSourceBase.cpp	Sat Nov 10 09:14:12 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "LayerSourceBase.h"
-
-#include <Core/OrthancException.h>
-
-namespace OrthancStone
-{
-  void LayerSourceBase::NotifyGeometryReady()
-  {
-    EmitMessage(ILayerSource::GeometryReadyMessage(*this));
-  }
-    
-  void LayerSourceBase::NotifyGeometryError()
-  {
-    EmitMessage(ILayerSource::GeometryErrorMessage(*this));
-  }
-    
-  void LayerSourceBase::NotifyContentChange()
-  {
-    EmitMessage(ILayerSource::ContentChangedMessage(*this));
-  }
-
-  void LayerSourceBase::NotifySliceChange(const Slice& slice)
-  {
-    EmitMessage(ILayerSource::SliceChangedMessage(*this, slice));
-  }
-
-  void LayerSourceBase::NotifyLayerReady(const LayerReadyMessage::IRendererFactory& factory,
-                                         const CoordinateSystem3D& slice)
-  {
-    EmitMessage(ILayerSource::LayerReadyMessage(*this, factory, slice));
-  }
-
-  void LayerSourceBase::NotifyLayerError(const CoordinateSystem3D& slice)
-  {
-    EmitMessage(ILayerSource::LayerErrorMessage(*this, slice));
-  }
-}
--- a/Framework/Layers/LayerSourceBase.h	Sat Nov 10 09:14:12 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "ILayerSource.h"
-#include "../Toolbox/ObserversRegistry.h"
-
-namespace OrthancStone
-{
-  class SmartLoader;
-
-  class LayerSourceBase : public ILayerSource
-  {
-  protected:
-    void NotifyGeometryReady();
-    
-    void NotifyGeometryError();
-
-    void NotifyContentChange();
-
-    void NotifySliceChange(const Slice& slice);
-
-    void NotifyLayerReady(const LayerReadyMessage::IRendererFactory& factory,
-                          const CoordinateSystem3D& slice);
-
-    void NotifyLayerError(const CoordinateSystem3D& slice);
-
-    LayerSourceBase(MessageBroker& broker) :
-      ILayerSource(broker)
-    {
-    }
-
-    friend class SmartLoader;
-  };
-}
--- a/Framework/Layers/OrthancFrameLayerSource.cpp	Sat Nov 10 09:14:12 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "OrthancFrameLayerSource.h"
-
-#include "FrameRenderer.h"
-#include "../Toolbox/DicomFrameConverter.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/lexical_cast.hpp>
-
-namespace OrthancStone
-{
-
-  void OrthancFrameLayerSource::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
-  {
-    if (message.GetOrigin().GetSliceCount() > 0)
-    {
-      LayerSourceBase::NotifyGeometryReady();
-    }
-    else
-    {
-      LayerSourceBase::NotifyGeometryError();
-    }
-  }
-
-  void OrthancFrameLayerSource::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
-  {
-    LayerSourceBase::NotifyGeometryError();
-  }
-
-
-  class OrthancFrameLayerSource::RendererFactory : public LayerReadyMessage::IRendererFactory
-  {
-  private:
-    const OrthancSlicesLoader::SliceImageReadyMessage&  message_;
-
-  public:
-    RendererFactory(const OrthancSlicesLoader::SliceImageReadyMessage& message) :
-      message_(message)
-    {
-    }
-
-    virtual ILayerRenderer* CreateRenderer() const
-    {
-      bool isFull = (message_.GetEffectiveQuality() == SliceImageQuality_FullPng ||
-                     message_.GetEffectiveQuality() == SliceImageQuality_FullPam);
-
-      return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull);
-    }
-  };
-
-  void OrthancFrameLayerSource::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
-  {
-    // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache)
-    EmitMessage(FrameReadyMessage(*this, message.GetImage(), 
-                                  message.GetEffectiveQuality(), message.GetSlice()));
-
-    // then notify that the layer is ready for render
-    RendererFactory factory(message);
-    LayerSourceBase::NotifyLayerReady(factory, message.GetSlice().GetGeometry());
-  }
-
-  void OrthancFrameLayerSource::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
-  {
-    LayerSourceBase::NotifyLayerError(message.GetSlice().GetGeometry());
-  }
-
-
-  OrthancFrameLayerSource::OrthancFrameLayerSource(MessageBroker& broker, OrthancApiClient& orthanc) :
-    LayerSourceBase(broker),
-    IObserver(broker),
-    loader_(broker, orthanc),
-    quality_(SliceImageQuality_FullPng)
-  {
-    loader_.RegisterObserverCallback(new Callable<OrthancFrameLayerSource, OrthancSlicesLoader::SliceGeometryReadyMessage>(*this, &OrthancFrameLayerSource::OnSliceGeometryReady));
-    loader_.RegisterObserverCallback(new Callable<OrthancFrameLayerSource, OrthancSlicesLoader::SliceGeometryErrorMessage>(*this, &OrthancFrameLayerSource::OnSliceGeometryError));
-    loader_.RegisterObserverCallback(new Callable<OrthancFrameLayerSource, OrthancSlicesLoader::SliceImageReadyMessage>(*this, &OrthancFrameLayerSource::OnSliceImageReady));
-    loader_.RegisterObserverCallback(new Callable<OrthancFrameLayerSource, OrthancSlicesLoader::SliceImageErrorMessage>(*this, &OrthancFrameLayerSource::OnSliceImageError));
-  }
-
-  
-  void OrthancFrameLayerSource::LoadSeries(const std::string& seriesId)
-  {
-    loader_.ScheduleLoadSeries(seriesId);
-  }
-
-
-  void OrthancFrameLayerSource::LoadInstance(const std::string& instanceId)
-  {
-    loader_.ScheduleLoadInstance(instanceId);
-  }
-
-
-  void OrthancFrameLayerSource::LoadFrame(const std::string& instanceId,
-                                          unsigned int frame)
-  {
-    loader_.ScheduleLoadFrame(instanceId, frame);
-  }
-
-
-  bool OrthancFrameLayerSource::GetExtent(std::vector<Vector>& points,
-                                          const CoordinateSystem3D& viewportSlice)
-  {
-    size_t index;
-
-    if (loader_.IsGeometryReady() &&
-        loader_.LookupSlice(index, viewportSlice))
-    {
-      loader_.GetSlice(index).GetExtent(points);
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-  
-  void OrthancFrameLayerSource::ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice)
-  {
-    size_t index;
-
-    if (loader_.IsGeometryReady() &&
-        loader_.LookupSlice(index, viewportSlice))
-    {
-      loader_.ScheduleLoadSliceImage(index, quality_);
-    }
-  }
-}
--- a/Framework/Layers/OrthancFrameLayerSource.h	Sat Nov 10 09:14:12 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "LayerSourceBase.h"
-#include "../Toolbox/IWebService.h"
-#include "../Toolbox/OrthancSlicesLoader.h"
-#include "../Toolbox/OrthancApiClient.h"
-
-namespace OrthancStone
-{  
-  // this class is in charge of loading a Frame.
-  // once it's been loaded (first the geometry and then the image),
-  // messages are sent to observers so they can use it
-  class OrthancFrameLayerSource :
-    public LayerSourceBase,
-    public IObserver
-    //private OrthancSlicesLoader::ISliceLoaderObserver
-  {
-  public:
-    // TODO: Add "frame" and "instanceId"
-    class FrameReadyMessage : public OriginMessage<MessageType_OrthancFrameLayerSource_FrameReady, OrthancFrameLayerSource>
-    {
-    private:
-      const Orthanc::ImageAccessor&  frame_;
-      SliceImageQuality              imageQuality_;
-      const Slice&                   slice_;
-
-    public:
-      FrameReadyMessage(OrthancFrameLayerSource& origin,
-                        const Orthanc::ImageAccessor& frame,
-                        SliceImageQuality imageQuality,
-                        const Slice& slice) :
-        OriginMessage(origin),
-        frame_(frame),
-        imageQuality_(imageQuality),
-        slice_(slice)
-      {
-      }
-
-      const Orthanc::ImageAccessor& GetFrame() const
-      {
-        return frame_;
-      }
-
-      SliceImageQuality GetImageQuality() const
-      {
-        return imageQuality_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-    
-  private:
-    class RendererFactory;
-    
-    OrthancSlicesLoader  loader_;
-    SliceImageQuality    quality_;
-
-  public:
-    OrthancFrameLayerSource(MessageBroker& broker, OrthancApiClient& orthanc);
-
-    void LoadSeries(const std::string& seriesId);
-
-    void LoadInstance(const std::string& instanceId);
-
-    void LoadFrame(const std::string& instanceId,
-                   unsigned int frame);
-
-    void SetImageQuality(SliceImageQuality quality)
-    {
-      quality_ = quality;
-    }
-
-    SliceImageQuality GetImageQuality() const
-    {
-      return quality_;
-    }
-
-    size_t GetSliceCount() const
-    {
-      return loader_.GetSliceCount();
-    }
-
-    const Slice& GetSlice(size_t slice) const 
-    {
-      return loader_.GetSlice(slice);
-    }
-
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice);
-
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice);
-
-protected:
-    void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message);
-    void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message);
-    void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message);
-    void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message);
-  };
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Layers/VolumeSlicerBase.cpp	Sat Nov 10 09:29:08 2018 +0100
@@ -0,0 +1,58 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "VolumeSlicerBase.h"
+
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  void VolumeSlicerBase::NotifyGeometryReady()
+  {
+    EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this));
+  }
+    
+  void VolumeSlicerBase::NotifyGeometryError()
+  {
+    EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this));
+  }
+    
+  void VolumeSlicerBase::NotifyContentChange()
+  {
+    EmitMessage(IVolumeSlicer::ContentChangedMessage(*this));
+  }
+
+  void VolumeSlicerBase::NotifySliceChange(const Slice& slice)
+  {
+    EmitMessage(IVolumeSlicer::SliceChangedMessage(*this, slice));
+  }
+
+  void VolumeSlicerBase::NotifyLayerReady(const LayerReadyMessage::IRendererFactory& factory,
+                                          const CoordinateSystem3D& slice)
+  {
+    EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice));
+  }
+
+  void VolumeSlicerBase::NotifyLayerError(const CoordinateSystem3D& slice)
+  {
+    EmitMessage(IVolumeSlicer::LayerErrorMessage(*this, slice));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Layers/VolumeSlicerBase.h	Sat Nov 10 09:29:08 2018 +0100
@@ -0,0 +1,54 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IVolumeSlicer.h"
+#include "../Toolbox/ObserversRegistry.h"
+
+namespace OrthancStone
+{
+  class SmartLoader;
+
+  class VolumeSlicerBase : public IVolumeSlicer
+  {
+  protected:
+    void NotifyGeometryReady();
+    
+    void NotifyGeometryError();
+
+    void NotifyContentChange();
+
+    void NotifySliceChange(const Slice& slice);
+
+    void NotifyLayerReady(const LayerReadyMessage::IRendererFactory& factory,
+                          const CoordinateSystem3D& slice);
+
+    void NotifyLayerError(const CoordinateSystem3D& slice);
+
+    VolumeSlicerBase(MessageBroker& broker) :
+      IVolumeSlicer(broker)
+    {
+    }
+
+    friend class SmartLoader;
+  };
+}
--- a/Framework/SmartLoader.cpp	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/SmartLoader.cpp	Sat Nov 10 09:29:08 2018 +0100
@@ -20,7 +20,7 @@
 
 
 #include "SmartLoader.h"
-#include "Layers/OrthancFrameLayerSource.h"
+#include "Layers/DicomSeriesVolumeSlicer.h"
 #include "Messages/MessageForwarder.h"
 #include "Core/Images/Image.h"
 #include "Framework/Widgets/SliceViewerWidget.h"
@@ -37,7 +37,7 @@
     CachedSliceStatus_ImageLoaded
   };
 
-  class SmartLoader::CachedSlice : public LayerSourceBase
+  class SmartLoader::CachedSlice : public VolumeSlicerBase
   {
   public:
     class RendererFactory : public LayerReadyMessage::IRendererFactory
@@ -68,7 +68,7 @@
 
   public:
     CachedSlice(MessageBroker& broker) :
-    LayerSourceBase(broker)
+    VolumeSlicerBase(broker)
     {
     }
 
@@ -89,13 +89,13 @@
       // TODO: viewportSlice is not used !!!!
 
       // it has already been loaded -> trigger the "layer ready" message immediately otherwise, do nothing now.  The LayerReady will be triggered
-      // once the LayerSource is ready
+      // once the VolumeSlicer is ready
       if (status_ == CachedSliceStatus_ImageLoaded)
       {
         LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId();
 
         RendererFactory factory(*this);
-        LayerSourceBase::NotifyLayerReady(factory, slice_->GetGeometry());
+        VolumeSlicerBase::NotifyLayerReady(factory, slice_->GetGeometry());
       }
       else
       {
@@ -135,11 +135,11 @@
     // TODO: check if this frame has already been loaded or is already being loaded.
     // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately"
     //   (it can not be immediate because Observers needs to register first and this is done after this method returns)
-    // - if currently loading, we need to return an object that will observe the existing LayerSource and forward
+    // - if currently loading, we need to return an object that will observe the existing VolumeSlicer and forward
     //   the messages to its observables
     // in both cases, we must be carefull about objects lifecycle !!!
 
-    std::auto_ptr<ILayerSource> layerSource;
+    std::auto_ptr<IVolumeSlicer> layerSource;
     std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
     SmartLoader::CachedSlice* cachedSlice = NULL;
 
@@ -150,12 +150,12 @@
     }
     else
     {
-      layerSource.reset(new OrthancFrameLayerSource(IObserver::GetBroker(), orthancApiClient_));
-      dynamic_cast<OrthancFrameLayerSource*>(layerSource.get())->SetImageQuality(imageQuality_);
-      layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
-      layerSource->RegisterObserverCallback(new Callable<SmartLoader, OrthancFrameLayerSource::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
-      layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
-      dynamic_cast<OrthancFrameLayerSource*>(layerSource.get())->LoadFrame(instanceId, frame);
+      layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
+      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
+      layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
+      layerSource->RegisterObserverCallback(new Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
+      layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
+      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
     }
 
     // make sure that the widget registers the events before we trigger them
@@ -182,7 +182,7 @@
   void SmartLoader::PreloadSlice(const std::string instanceId, 
                                  unsigned int frame)
   {
-    // TODO: reactivate -> need to be able to ScheduleLayerLoading in ILayerSource without calling ScheduleLayerCreation
+    // TODO: reactivate -> need to be able to ScheduleLayerLoading in IVolumeSlicer without calling ScheduleLayerCreation
     return;
     // TODO: check if it is already in the cache
 
@@ -198,16 +198,16 @@
 
     cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
 
-    std::auto_ptr<ILayerSource> layerSource(new OrthancFrameLayerSource(IObserver::GetBroker(), orthancApiClient_));
+    std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
 
-    dynamic_cast<OrthancFrameLayerSource*>(layerSource.get())->SetImageQuality(imageQuality_);
-    layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
-    layerSource->RegisterObserverCallback(new Callable<SmartLoader, OrthancFrameLayerSource::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
-    layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
-    dynamic_cast<OrthancFrameLayerSource*>(layerSource.get())->LoadFrame(instanceId, frame);
+    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
+    layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
+    layerSource->RegisterObserverCallback(new Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
+    layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
+    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
 
-    // keep a ref to the LayerSource until the slice is fully loaded and saved to cache
-    preloadingInstances_[sliceKeyId] = boost::shared_ptr<ILayerSource>(layerSource.release());
+    // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache
+    preloadingInstances_[sliceKeyId] = boost::shared_ptr<IVolumeSlicer>(layerSource.release());
   }
 
 
@@ -222,9 +222,9 @@
 //  }
 
 
-  void SmartLoader::OnLayerGeometryReady(const ILayerSource::GeometryReadyMessage& message)
+  void SmartLoader::OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
   {
-    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.GetOrigin());
+    DicomSeriesVolumeSlicer& source = dynamic_cast<DicomSeriesVolumeSlicer&>(message.GetOrigin());
 
     // save/replace the slice in cache
     const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount()
@@ -245,7 +245,7 @@
   }
 
 
-  void SmartLoader::OnFrameReady(const OrthancFrameLayerSource::FrameReadyMessage& message)
+  void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message)
   {
     // save/replace the slice in cache
     const Slice& slice = message.GetSlice();
@@ -267,9 +267,9 @@
   }
 
 
-  void SmartLoader::OnLayerReady(const ILayerSource::LayerReadyMessage& message)
+  void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
   {
-    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.GetOrigin());
+    DicomSeriesVolumeSlicer& source = dynamic_cast<DicomSeriesVolumeSlicer&>(message.GetOrigin());
     const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ?
     std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
                               boost::lexical_cast<std::string>(slice.GetFrame()));
--- a/Framework/SmartLoader.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/SmartLoader.h	Sat Nov 10 09:29:08 2018 +0100
@@ -22,7 +22,7 @@
 #pragma once
 #include <map>
 
-#include "Layers/OrthancFrameLayerSource.h"
+#include "Layers/DicomSeriesVolumeSlicer.h"
 #include "Messages/IObservable.h"
 #include "Toolbox/OrthancApiClient.h"
 
@@ -38,7 +38,7 @@
     typedef std::map<std::string, boost::shared_ptr<SmartLoader::CachedSlice> > CachedSlices;
     CachedSlices cachedSlices_;
 
-    typedef std::map<std::string, boost::shared_ptr<ILayerSource> > PreloadingInstances;
+    typedef std::map<std::string, boost::shared_ptr<IVolumeSlicer> > PreloadingInstances;
     PreloadingInstances preloadingInstances_;
 
     SliceImageQuality     imageQuality_;
@@ -58,9 +58,9 @@
     void GetFirstInstanceIdForSeries(std::string& output, const std::string& seriesId);
 
   private:
-    void OnLayerGeometryReady(const ILayerSource::GeometryReadyMessage& message);
-    void OnFrameReady(const OrthancFrameLayerSource::FrameReadyMessage& message);
-    void OnLayerReady(const ILayerSource::LayerReadyMessage& message);
+    void OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
+    void OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message);
+    void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message);
 
   };
 
--- a/Framework/StoneEnumerations.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/StoneEnumerations.h	Sat Nov 10 09:29:08 2018 +0100
@@ -127,7 +127,7 @@
     MessageType_LayerSource_LayerReady,      // layer is ready to be rendered
     MessageType_LayerSource_LayerError,
 
-    MessageType_OrthancFrameLayerSource_FrameReady,      // pixels data of the frame have been loaded
+    MessageType_DicomSeriesVolumeSlicer_FrameReady,      // pixels data of the frame have been loaded
 
     MessageType_SliceLoader_GeometryReady,
     MessageType_SliceLoader_GeometryError,
--- a/Framework/Widgets/SliceViewerWidget.cpp	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/Widgets/SliceViewerWidget.cpp	Sat Nov 10 09:29:08 2018 +0100
@@ -237,7 +237,7 @@
 
   
   bool SliceViewerWidget::LookupLayer(size_t& index /* out */,
-                                      const ILayerSource& layer) const
+                                      const IVolumeSlicer& layer) const
   {
     LayersIndex::const_iterator found = layersIndex_.find(&layer);
 
@@ -256,7 +256,7 @@
 
 
   void SliceViewerWidget::GetLayerExtent(Extent2D& extent,
-                                         ILayerSource& source) const
+                                         IVolumeSlicer& source) const
   {
     extent.Reset();
 
@@ -382,23 +382,23 @@
     }
   }
   
-  void SliceViewerWidget::ObserveLayer(ILayerSource& layer)
+  void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer)
   {
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, ILayerSource::GeometryReadyMessage>
+    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage>
                                    (*this, &SliceViewerWidget::OnGeometryReady));
-    // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, ILayerSource::GeometryErrorMessage>(*this, &SliceViewerWidget::...));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, ILayerSource::SliceChangedMessage>
+    // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryErrorMessage>(*this, &SliceViewerWidget::...));
+    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::SliceChangedMessage>
                                    (*this, &SliceViewerWidget::OnSliceChanged));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, ILayerSource::ContentChangedMessage>
+    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage>
                                    (*this, &SliceViewerWidget::OnContentChanged));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, ILayerSource::LayerReadyMessage>
+    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage>
                                    (*this, &SliceViewerWidget::OnLayerReady));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, ILayerSource::LayerErrorMessage>
+    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage>
                                    (*this, &SliceViewerWidget::OnLayerError));
   }
 
 
-  size_t SliceViewerWidget::AddLayer(ILayerSource* layer)  // Takes ownership
+  size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer)  // Takes ownership
   {
     if (layer == NULL)
     {
@@ -420,7 +420,7 @@
   }
 
 
-  void SliceViewerWidget::ReplaceLayer(size_t index, ILayerSource* layer)  // Takes ownership
+  void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer)  // Takes ownership
   {
     if (layer == NULL)
     {
@@ -451,7 +451,7 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    ILayerSource* previousLayer = layers_[index];
+    IVolumeSlicer* previousLayer = layers_[index];
     layersIndex_.erase(layersIndex_.find(previousLayer));
     layers_.erase(layers_.begin() + index);
     changedLayers_.erase(changedLayers_.begin() + index);
@@ -528,7 +528,7 @@
   }
 
 
-  void SliceViewerWidget::OnGeometryReady(const ILayerSource::GeometryReadyMessage& message)
+  void SliceViewerWidget::OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
   {
     size_t i;
     if (LookupLayer(i, message.GetOrigin()))
@@ -568,7 +568,7 @@
   }
 
 
-  void SliceViewerWidget::OnContentChanged(const ILayerSource::ContentChangedMessage& message)
+  void SliceViewerWidget::OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message)
   {
     size_t index;
     if (LookupLayer(index, message.GetOrigin()))
@@ -580,7 +580,7 @@
   }
   
 
-  void SliceViewerWidget::OnSliceChanged(const ILayerSource::SliceChangedMessage& message)
+  void SliceViewerWidget::OnSliceChanged(const IVolumeSlicer::SliceChangedMessage& message)
   {
     if (message.GetSlice().ContainsPlane(plane_))
     {
@@ -595,7 +595,7 @@
   }
   
   
-  void SliceViewerWidget::OnLayerReady(const ILayerSource::LayerReadyMessage& message)
+  void SliceViewerWidget::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
   {
     size_t index;
     if (LookupLayer(index, message.GetOrigin()))
@@ -608,7 +608,7 @@
   }
 
 
-  void SliceViewerWidget::OnLayerError(const ILayerSource::LayerErrorMessage& message)
+  void SliceViewerWidget::OnLayerError(const IVolumeSlicer::LayerErrorMessage& message)
   {
     size_t index;
     if (LookupLayer(index, message.GetOrigin()))
--- a/Framework/Widgets/SliceViewerWidget.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/Widgets/SliceViewerWidget.h	Sat Nov 10 09:29:08 2018 +0100
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "WorldSceneWidget.h"
-#include "../Layers/ILayerSource.h"
+#include "../Layers/IVolumeSlicer.h"
 #include "../Toolbox/Extent2D.h"
 #include "../../Framework/Messages/IObserver.h"
 
@@ -42,34 +42,34 @@
   private:
     class Scene;
     
-    typedef std::map<const ILayerSource*, size_t>  LayersIndex;
+    typedef std::map<const IVolumeSlicer*, size_t>  LayersIndex;
 
-    bool                        started_;
-    LayersIndex                 layersIndex_;
-    std::vector<ILayerSource*>  layers_;
-    std::vector<RenderStyle>    styles_;
-    CoordinateSystem3D          plane_;
-    std::auto_ptr<Scene>        currentScene_;
-    std::auto_ptr<Scene>        pendingScene_;
-    std::vector<bool>           changedLayers_;
+    bool                         started_;
+    LayersIndex                  layersIndex_;
+    std::vector<IVolumeSlicer*>  layers_;
+    std::vector<RenderStyle>     styles_;
+    CoordinateSystem3D           plane_;
+    std::auto_ptr<Scene>         currentScene_;
+    std::auto_ptr<Scene>         pendingScene_;
+    std::vector<bool>            changedLayers_;
 
     bool LookupLayer(size_t& index /* out */,
-                     const ILayerSource& layer) const;
+                     const IVolumeSlicer& layer) const;
 
     void GetLayerExtent(Extent2D& extent,
-                        ILayerSource& source) const;
+                        IVolumeSlicer& source) const;
 
-    void OnGeometryReady(const ILayerSource::GeometryReadyMessage& message);
+    void OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
 
-    virtual void OnContentChanged(const ILayerSource::ContentChangedMessage& message);
+    virtual void OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message);
 
-    virtual void OnSliceChanged(const ILayerSource::SliceChangedMessage& message);
+    virtual void OnSliceChanged(const IVolumeSlicer::SliceChangedMessage& message);
 
-    virtual void OnLayerReady(const ILayerSource::LayerReadyMessage& message);
+    virtual void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message);
 
-    virtual void OnLayerError(const ILayerSource::LayerErrorMessage& message);
+    virtual void OnLayerError(const IVolumeSlicer::LayerErrorMessage& message);
 
-    void ObserveLayer(ILayerSource& source);
+    void ObserveLayer(IVolumeSlicer& source);
 
     void ResetChangedLayers();
 
@@ -96,9 +96,9 @@
   public:
     virtual ~SliceViewerWidget();
 
-    size_t AddLayer(ILayerSource* layer);  // Takes ownership
+    size_t AddLayer(IVolumeSlicer* layer);  // Takes ownership
 
-    void ReplaceLayer(size_t layerIndex, ILayerSource* layer); // Takes ownership
+    void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership
 
     void RemoveLayer(size_t layerIndex);
 
--- a/Framework/dev.h	Sat Nov 10 09:14:12 2018 +0100
+++ b/Framework/dev.h	Sat Nov 10 09:29:08 2018 +0100
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "Layers/FrameRenderer.h"
-#include "Layers/LayerSourceBase.h"
+#include "Layers/VolumeSlicerBase.h"
 #include "Layers/SliceOutlineRenderer.h"
 #include "Layers/LineLayerRenderer.h"
 #include "Widgets/SliceViewerWidget.h"
@@ -495,7 +495,7 @@
 
 
   class VolumeImageSource :
-      public LayerSourceBase,
+      public VolumeSlicerBase,
       private ISlicedVolume::IObserver
   {
   private:
@@ -537,32 +537,32 @@
     
     virtual void NotifyGeometryReady(const ISlicedVolume& volume)
     {
-      // These 3 values are only used to speed up the ILayerSource
+      // These 3 values are only used to speed up the IVolumeSlicer
       axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial));
       coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal));
       sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal));
       
-      LayerSourceBase::NotifyGeometryReady();
+      VolumeSlicerBase::NotifyGeometryReady();
     }
 
     virtual void NotifyGeometryError(const ISlicedVolume& volume)
     {
-      LayerSourceBase::NotifyGeometryError();
+      VolumeSlicerBase::NotifyGeometryError();
     }
 
     virtual void NotifyContentChange(const ISlicedVolume& volume)
     {
-      LayerSourceBase::NotifyContentChange();
+      VolumeSlicerBase::NotifyContentChange();
     }
 
     virtual void NotifySliceChange(const ISlicedVolume& volume,
                                    const size_t& sliceIndex,
                                    const Slice& slice)
     {
-      //LayerSourceBase::NotifySliceChange(slice);
+      //VolumeSlicerBase::NotifySliceChange(slice);
 
       // TODO Improve this?
-      LayerSourceBase::NotifyContentChange();
+      VolumeSlicerBase::NotifyContentChange();
     }
 
     virtual void NotifyVolumeReady(const ISlicedVolume& volume)
@@ -628,7 +628,7 @@
 
   public:
     VolumeImageSource(MessageBroker& broker, OrthancVolumeImage&  volume) :
-      LayerSourceBase(broker),
+      VolumeSlicerBase(broker),
       volume_(volume)
     {
       volume_.Register(*this);
@@ -683,7 +683,7 @@
           std::auto_ptr<Slice> slice(geometry.GetSlice(closest));
 
           RendererFactory factory(*frame, *slice, isFullQuality);
-          LayerSourceBase::NotifyLayerReady(factory,
+          VolumeSlicerBase::NotifyLayerReady(factory,
             //new SliceOutlineRenderer(slice),
             slice->GetGeometry());
           return;
@@ -692,7 +692,7 @@
 
       // Error
       CoordinateSystem3D slice;
-      LayerSourceBase::NotifyLayerError(slice);
+      VolumeSlicerBase::NotifyLayerError(slice);
     }
   };
 
@@ -862,7 +862,7 @@
 
 
 
-  class ReferenceLineSource : public LayerSourceBase
+  class ReferenceLineSource : public VolumeSlicerBase
   {
   private:
     class RendererFactory : public LayerReadyMessage::IRendererFactory
@@ -899,7 +899,7 @@
   public:
     ReferenceLineSource(MessageBroker& broker, 
                         SliceViewerWidget&  otherPlane) :
-      LayerSourceBase(broker),
+      VolumeSlicerBase(broker),
       otherPlane_(otherPlane)
     {
       NotifyGeometryReady();
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Sat Nov 10 09:14:12 2018 +0100
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Sat Nov 10 09:29:08 2018 +0100
@@ -240,11 +240,11 @@
   ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomStructureSetRendererFactory.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/FrameRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/GrayscaleFrameRenderer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/ILayerSource.h
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/LayerSourceBase.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Layers/IVolumeSlicer.h
+  ${ORTHANC_STONE_ROOT}/Framework/Layers/VolumeSlicerBase.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineLayerRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/OrthancFrameLayerSource.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomSeriesVolumeSlicer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/RenderStyle.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/SliceOutlineRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/SmartLoader.cpp
--- a/UnitTestsSources/UnitTestsMain.cpp	Sat Nov 10 09:14:12 2018 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Sat Nov 10 09:29:08 2018 +0100
@@ -23,7 +23,6 @@
 #include "gtest/gtest.h"
 
 #include "../Framework/Layers/FrameRenderer.h"
-#include "../Framework/Layers/LayerSourceBase.h"
 #include "../Framework/Toolbox/DownloadStack.h"
 #include "../Framework/Toolbox/FiniteProjectiveCamera.h"
 #include "../Framework/Toolbox/MessagingToolbox.h"