changeset 728:8190213e2279 am-dev

Merged default into am-dev
author Alain Mazy <am@osimis.io>
date Tue, 21 May 2019 13:25:58 +0200
parents f185cfcb72a0 (current diff) 853e30d17cae (diff)
children 529189f399ec fe938bddb932
files Applications/Samples/SimpleViewer/Messages.h Samples/Common/AngleMeasureTool.cpp Samples/Common/AngleMeasureTool.h Samples/Common/CreateAngleMeasureTracker.cpp Samples/Common/CreateAngleMeasureTracker.h Samples/Common/CreateCircleMeasureTracker.cpp Samples/Common/CreateCircleMeasureTracker.h Samples/Common/CreateLineMeasureTracker.cpp Samples/Common/CreateLineMeasureTracker.h Samples/Common/CreateMeasureTracker.cpp Samples/Common/CreateMeasureTracker.h Samples/Common/CreateSimpleTrackerAdapter.cpp Samples/Common/EditAngleMeasureTracker.cpp Samples/Common/EditAngleMeasureTracker.h Samples/Common/EditCircleMeasureTracker.cpp Samples/Common/EditCircleMeasureTracker.h Samples/Common/EditLineMeasureTracker.cpp Samples/Common/EditLineMeasureTracker.h Samples/Common/IFlexiblePointerTracker.h Samples/Common/LineMeasureTool.cpp Samples/Common/LineMeasureTool.h Samples/Common/MeasureCommands.cpp Samples/Common/MeasureCommands.h Samples/Common/MeasureTools.cpp Samples/Common/MeasureTools.h Samples/Common/MeasureToolsToolbox.cpp Samples/Common/MeasureToolsToolbox.h Samples/Common/MeasureTrackers.cpp Samples/Common/MeasureTrackers.h
diffstat 252 files changed, 7193 insertions(+), 4673 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Generic/NativeStoneApplicationContext.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationContext.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 
 namespace OrthancStone
 {
-  IWidget& NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(IWidget* widget)
+  Deprecated::IWidget& NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(Deprecated::IWidget* widget)
   {
     that_.centralViewport_.SetCentralWidget(widget);
     return *widget;
--- a/Applications/Generic/NativeStoneApplicationContext.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationContext.h	Tue May 21 13:25:58 2019 +0200
@@ -37,7 +37,7 @@
     static void UpdateThread(NativeStoneApplicationContext* that);
 
     boost::recursive_mutex    globalMutex_;
-    WidgetViewport  centralViewport_;
+    Deprecated::WidgetViewport  centralViewport_;
     boost::thread   updateThread_;
     bool            stopped_;
     unsigned int    updateDelayInMs_;
@@ -56,9 +56,9 @@
       {
       }
 
-      IWidget& SetCentralWidget(IWidget* widget);   // Takes ownership
+      Deprecated::IWidget& SetCentralWidget(Deprecated::IWidget* widget);   // Takes ownership
 
-      IViewport& GetCentralViewport() 
+      Deprecated::IViewport& GetCentralViewport() 
       {
         return that_.centralViewport_;
       }
--- a/Applications/Generic/NativeStoneApplicationRunner.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationRunner.cpp	Tue May 21 13:25:58 2019 +0200
@@ -43,7 +43,7 @@
   // Anonymous namespace to avoid clashes against other compilation modules
   namespace
   {
-    class LogStatusBar : public IStatusBar
+    class LogStatusBar : public Deprecated::IStatusBar
     {
     public:
       virtual void ClearMessage()
@@ -202,17 +202,17 @@
       {
         // use multiple threads to execute asynchronous tasks like 
         // download content
-        Oracle oracle(6); 
+        Deprecated::Oracle oracle(6); 
         oracle.Start();
 
         {
-          OracleWebService webService(
+          Deprecated::OracleWebService webService(
             broker_, oracle, webServiceParameters, context);
           
           context.SetWebService(webService);
           context.SetOrthancBaseUrl(webServiceParameters.GetUrl());
 
-          OracleDelayedCallExecutor delayedExecutor(broker_, oracle, context);
+          Deprecated::OracleDelayedCallExecutor delayedExecutor(broker_, oracle, context);
           context.SetDelayedCallExecutor(delayedExecutor);
 
           application_.Initialize(&context, statusBar, parameters);
--- a/Applications/IStoneApplication.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/IStoneApplication.h	Tue May 21 13:25:58 2019 +0200
@@ -47,7 +47,7 @@
 
     virtual void DeclareStartupOptions(boost::program_options::options_description& options) = 0;
     virtual void Initialize(StoneApplicationContext* context,
-                            IStatusBar& statusBar,
+                            Deprecated::IStatusBar& statusBar,
                             const boost::program_options::variables_map& parameters) = 0;
 
     /**
@@ -63,7 +63,7 @@
 #endif
 
     virtual std::string GetTitle() const = 0;
-    virtual IWidget* GetCentralWidget() = 0;
+    virtual Deprecated::IWidget* GetCentralWidget() = 0;
     virtual void Finalize() = 0;
   };
 }
--- a/Applications/Samples/CMakeLists.txt	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/CMakeLists.txt	Tue May 21 13:25:58 2019 +0200
@@ -228,6 +228,7 @@
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestExceptions.cpp
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStrategy.cpp
     ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
     )
 
--- a/Applications/Samples/SampleApplicationBase.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SampleApplicationBase.h	Tue May 21 13:25:58 2019 +0200
@@ -42,11 +42,11 @@
     {
     protected:
       // ownership is transferred to the application context
-      WorldSceneWidget*  mainWidget_;
+      Deprecated::WorldSceneWidget*  mainWidget_;
 
     public:
       virtual void Initialize(StoneApplicationContext* context,
-                              IStatusBar& statusBar,
+                              Deprecated::IStatusBar& statusBar,
                               const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE
       {
       }
@@ -64,7 +64,7 @@
 
 
       virtual void Finalize() ORTHANC_OVERRIDE {}
-      virtual IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainWidget_;}
+      virtual Deprecated::IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainWidget_;}
 
 #if ORTHANC_ENABLE_WASM==1
       // default implementations for a single canvas named "canvas" in the HTML and an emtpy WasmApplicationAdapter
--- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,27 +24,27 @@
 
 namespace SimpleViewer {
 
-  IWorldSceneMouseTracker* MainWidgetInteractor::CreateMouseTracker(WorldSceneWidget& widget,
-                                                                    const ViewportGeometry& view,
+  Deprecated::IWorldSceneMouseTracker* MainWidgetInteractor::CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                    const Deprecated::ViewportGeometry& view,
                                                                     MouseButton button,
                                                                     KeyboardModifiers modifiers,
                                                                     int viewportX,
                                                                     int viewportY,
                                                                     double x,
                                                                     double y,
-                                                                    IStatusBar* statusBar,
-                                                                    const std::vector<Touch>& displayTouches)
+                                                                    Deprecated::IStatusBar* statusBar,
+                                                                    const std::vector<Deprecated::Touch>& displayTouches)
   {
     if (button == MouseButton_Left)
     {
       if (application_.GetCurrentTool() == Tool_LineMeasure)
       {
-        return new LineMeasureTracker(statusBar, dynamic_cast<SliceViewerWidget&>(widget).GetSlice(),
+        return new Deprecated::LineMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
                                       x, y, 255, 0, 0, application_.GetFont());
       }
       else if (application_.GetCurrentTool() == Tool_CircleMeasure)
       {
-        return new CircleMeasureTracker(statusBar, dynamic_cast<SliceViewerWidget&>(widget).GetSlice(),
+        return new Deprecated::CircleMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
                                         x, y, 255, 0, 0, application_.GetFont());
       }
       else if (application_.GetCurrentTool() == Tool_Crop)
@@ -68,15 +68,15 @@
   }
 
   void MainWidgetInteractor::MouseOver(CairoContext& context,
-                                       WorldSceneWidget& widget,
-                                       const ViewportGeometry& view,
+                                       Deprecated::WorldSceneWidget& widget,
+                                       const Deprecated::ViewportGeometry& view,
                                        double x,
                                        double y,
-                                       IStatusBar* statusBar)
+                                       Deprecated::IStatusBar* statusBar)
   {
     if (statusBar != NULL)
     {
-      Vector p = dynamic_cast<SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+      Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
 
       char buf[64];
       sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
@@ -85,18 +85,18 @@
     }
   }
 
-  void MainWidgetInteractor::MouseWheel(WorldSceneWidget& widget,
+  void MainWidgetInteractor::MouseWheel(Deprecated::WorldSceneWidget& widget,
                                         MouseWheelDirection direction,
                                         KeyboardModifiers modifiers,
-                                        IStatusBar* statusBar)
+                                        Deprecated::IStatusBar* statusBar)
   {
   }
 
-  void MainWidgetInteractor::KeyPressed(WorldSceneWidget& widget,
+  void MainWidgetInteractor::KeyPressed(Deprecated::WorldSceneWidget& widget,
                                         KeyboardKeys key,
                                         char keyChar,
                                         KeyboardModifiers modifiers,
-                                        IStatusBar* statusBar)
+                                        Deprecated::IStatusBar* statusBar)
   {
     switch (keyChar)
     {
--- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.h	Tue May 21 13:25:58 2019 +0200
@@ -28,7 +28,7 @@
 
   class SimpleViewerApplication;
 
-  class MainWidgetInteractor : public IWorldSceneInteractor
+  class MainWidgetInteractor : public Deprecated::IWorldSceneInteractor
   {
   private:
     SimpleViewerApplication&  application_;
@@ -42,34 +42,34 @@
     /**
         WorldSceneWidget: 
     */
-    virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                        const ViewportGeometry& view,
-                                                        MouseButton button,
-                                                        KeyboardModifiers modifiers,
-                                                        int viewportX,
-                                                        int viewportY,
-                                                        double x,
-                                                        double y,
-                                                        IStatusBar* statusBar,
-                                                        const std::vector<Touch>& displayTouches);
+    virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                    const Deprecated::ViewportGeometry& view,
+                                                                    MouseButton button,
+                                                                    KeyboardModifiers modifiers,
+                                                                    int viewportX,
+                                                                    int viewportY,
+                                                                    double x,
+                                                                    double y,
+                                                                    Deprecated::IStatusBar* statusBar,
+                                                                    const std::vector<Deprecated::Touch>& displayTouches);
 
     virtual void MouseOver(CairoContext& context,
-                           WorldSceneWidget& widget,
-                           const ViewportGeometry& view,
+                           Deprecated::WorldSceneWidget& widget,
+                           const Deprecated::ViewportGeometry& view,
                            double x,
                            double y,
-                           IStatusBar* statusBar);
+                           Deprecated::IStatusBar* statusBar);
 
-    virtual void MouseWheel(WorldSceneWidget& widget,
+    virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
                             MouseWheelDirection direction,
                             KeyboardModifiers modifiers,
-                            IStatusBar* statusBar);
+                            Deprecated::IStatusBar* statusBar);
 
-    virtual void KeyPressed(WorldSceneWidget& widget,
+    virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
                             KeyboardKeys key,
                             char keyChar,
                             KeyboardModifiers modifiers,
-                            IStatusBar* statusBar);
+                            Deprecated::IStatusBar* statusBar);
   };
 
 
--- a/Applications/Samples/SimpleViewer/Messages.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-#pragma once
-
-namespace SimpleViewer
-{
-  enum SimpleViewerMessageType
-  {
-    SimpleViewerMessageType_First = OrthancStone::MessageType_CustomMessage,
-    SimpleViewerMessageType_AppStatusUpdated
-  };
-}
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp	Tue May 21 13:25:58 2019 +0200
@@ -33,28 +33,26 @@
 {
 
   void SimpleViewerApplication::Initialize(StoneApplicationContext* context,
-                                           IStatusBar& statusBar,
+                                           Deprecated::IStatusBar& statusBar,
                                            const boost::program_options::variables_map& parameters)
   {
-    using namespace OrthancStone;
-
     context_ = context;
     statusBar_ = &statusBar;
 
     {// initialize viewports and layout
-      mainLayout_ = new LayoutWidget("main-layout");
+      mainLayout_ = new Deprecated::LayoutWidget("main-layout");
       mainLayout_->SetPadding(10);
       mainLayout_->SetBackgroundCleared(true);
       mainLayout_->SetBackgroundColor(0, 0, 0);
       mainLayout_->SetHorizontal();
 
-      thumbnailsLayout_ = new LayoutWidget("thumbnail-layout");
+      thumbnailsLayout_ = new Deprecated::LayoutWidget("thumbnail-layout");
       thumbnailsLayout_->SetPadding(10);
       thumbnailsLayout_->SetBackgroundCleared(true);
       thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
       thumbnailsLayout_->SetVertical();
 
-      mainWidget_ = new SliceViewerWidget(IObserver::GetBroker(), "main-viewport");
+      mainWidget_ = new Deprecated::SliceViewerWidget(IObserver::GetBroker(), "main-viewport");
       //mainWidget_->RegisterObserver(*this);
 
       // hierarchy
@@ -62,7 +60,7 @@
       mainLayout_->AddWidget(mainWidget_);
 
       // sources
-      smartLoader_.reset(new SmartLoader(IObserver::GetBroker(), context->GetOrthancApiClient()));
+      smartLoader_.reset(new Deprecated::SmartLoader(IObserver::GetBroker(), context->GetOrthancApiClient()));
       smartLoader_->SetImageQuality(SliceImageQuality_FullPam);
 
       mainLayout_->SetTransmitMouseOver(true);
@@ -78,7 +76,7 @@
     if (parameters.count("studyId") < 1)
     {
       LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
-      context->GetOrthancApiClient().GetJsonAsync("/studies", new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyListReceived));
+      context->GetOrthancApiClient().GetJsonAsync("/studies", new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyListReceived));
     }
     else
     {
@@ -98,7 +96,7 @@
     options.add(generic);
   }
 
-  void SimpleViewerApplication::OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
+  void SimpleViewerApplication::OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
   {
     const Json::Value& response = message.GetJson();
 
@@ -108,7 +106,7 @@
       SelectStudy(response[0].asString());
     }
   }
-  void SimpleViewerApplication::OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
+  void SimpleViewerApplication::OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
   {
     const Json::Value& response = message.GetJson();
 
@@ -116,12 +114,12 @@
     {
       for (size_t i=0; i < response["Series"].size(); i++)
       {
-        context_->GetOrthancApiClient().GetJsonAsync("/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnSeriesReceived));
+        context_->GetOrthancApiClient().GetJsonAsync("/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnSeriesReceived));
       }
     }
   }
 
-  void SimpleViewerApplication::OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
+  void SimpleViewerApplication::OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
   {
     const Json::Value& response = message.GetJson();
 
@@ -154,13 +152,13 @@
   {
     LOG(INFO) << "Loading thumbnail for series " << seriesId;
     
-    SliceViewerWidget* thumbnailWidget = 
-      new SliceViewerWidget(IObserver::GetBroker(), "thumbnail-series-" + seriesId);
+    Deprecated::SliceViewerWidget* thumbnailWidget = 
+      new Deprecated::SliceViewerWidget(IObserver::GetBroker(), "thumbnail-series-" + seriesId);
     thumbnails_.push_back(thumbnailWidget);
     thumbnailsLayout_->AddWidget(thumbnailWidget);
     
     thumbnailWidget->RegisterObserverCallback(
-      new Callable<SimpleViewerApplication, SliceViewerWidget::GeometryChangedMessage>
+      new Callable<SimpleViewerApplication, Deprecated::SliceViewerWidget::GeometryChangedMessage>
       (*this, &SimpleViewerApplication::OnWidgetGeometryChanged));
     
     smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
@@ -169,13 +167,13 @@
 
   void SimpleViewerApplication::SelectStudy(const std::string& studyId)
   {
-    context_->GetOrthancApiClient().GetJsonAsync("/studies/" + studyId, new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyReceived));
+    context_->GetOrthancApiClient().GetJsonAsync("/studies/" + studyId, new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyReceived));
   }
 
-  void SimpleViewerApplication::OnWidgetGeometryChanged(const SliceViewerWidget::GeometryChangedMessage& message)
+  void SimpleViewerApplication::OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
   {
     // TODO: The "const_cast" could probably be replaced by "mainWidget_"
-    const_cast<SliceViewerWidget&>(message.GetOrigin()).FitContent();
+    const_cast<Deprecated::SliceViewerWidget&>(message.GetOrigin()).FitContent();
   }
 
   void SimpleViewerApplication::SelectSeriesInMainViewport(const std::string& seriesId)
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Tue May 21 13:25:58 2019 +0200
@@ -51,7 +51,6 @@
 #include "ThumbnailInteractor.h"
 #include "MainWidgetInteractor.h"
 #include "AppStatus.h"
-#include "Messages.h"
 
 using namespace OrthancStone;
 
@@ -67,13 +66,14 @@
   {
   public:
 
-    struct StatusUpdatedMessage : public BaseMessage<SimpleViewerMessageType_AppStatusUpdated>
+    struct StatusUpdatedMessage : public IMessage
     {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
       const AppStatus& status_;
 
       StatusUpdatedMessage(const AppStatus& status)
-        : BaseMessage(),
-          status_(status)
+        : status_(status)
       {
       }
     };
@@ -83,18 +83,18 @@
 
     std::auto_ptr<MainWidgetInteractor> mainWidgetInteractor_;
     std::auto_ptr<ThumbnailInteractor>  thumbnailInteractor_;
-    LayoutWidget*                       mainLayout_;
-    LayoutWidget*                       thumbnailsLayout_;
-    SliceViewerWidget*                  mainWidget_;
-    std::vector<SliceViewerWidget*>     thumbnails_;
+    Deprecated::LayoutWidget*                       mainLayout_;
+    Deprecated::LayoutWidget*                       thumbnailsLayout_;
+    Deprecated::SliceViewerWidget*                  mainWidget_;
+    std::vector<Deprecated::SliceViewerWidget*>     thumbnails_;
     std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
     std::map<std::string, Json::Value>  seriesTags_;
     unsigned int                        currentInstanceIndex_;
-    OrthancStone::WidgetViewport*       wasmViewport1_;
-    OrthancStone::WidgetViewport*       wasmViewport2_;
+    Deprecated::WidgetViewport*       wasmViewport1_;
+    Deprecated::WidgetViewport*       wasmViewport2_;
 
-    IStatusBar*                         statusBar_;
-    std::auto_ptr<SmartLoader>          smartLoader_;
+    Deprecated::IStatusBar*                         statusBar_;
+    std::auto_ptr<Deprecated::SmartLoader>          smartLoader_;
 
     Orthanc::Font                       font_;
 
@@ -112,24 +112,24 @@
     }
 
     virtual void Finalize() ORTHANC_OVERRIDE {}
-    virtual IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainLayout_;}
+    virtual Deprecated::IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainLayout_;}
 
     virtual void DeclareStartupOptions(boost::program_options::options_description& options) ORTHANC_OVERRIDE;
     virtual void Initialize(StoneApplicationContext* context,
-                            IStatusBar& statusBar,
+                            Deprecated::IStatusBar& statusBar,
                             const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE;
 
-    void OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message);
+    void OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
 
-    void OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message);
+    void OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
 
-    void OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message);
+    void OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
 
     void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId);
 
     void SelectStudy(const std::string& studyId);
 
-    void OnWidgetGeometryChanged(const SliceViewerWidget::GeometryChangedMessage& message);
+    void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message);
 
     void SelectSeriesInMainViewport(const std::string& seriesId);
 
--- a/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,16 +24,16 @@
 
 namespace SimpleViewer {
 
-  IWorldSceneMouseTracker* ThumbnailInteractor::CreateMouseTracker(WorldSceneWidget& widget,
-                                                                   const ViewportGeometry& view,
+  Deprecated::IWorldSceneMouseTracker* ThumbnailInteractor::CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                   const Deprecated::ViewportGeometry& view,
                                                                    MouseButton button,
                                                                    KeyboardModifiers modifiers,
                                                                    int viewportX,
                                                                    int viewportY,
                                                                    double x,
                                                                    double y,
-                                                                   IStatusBar* statusBar,
-                                                                   const std::vector<Touch>& displayTouches)
+                                                                   Deprecated::IStatusBar* statusBar,
+                                                                   const std::vector<Deprecated::Touch>& displayTouches)
   {
     if (button == MouseButton_Left)
     {
--- a/Applications/Samples/SimpleViewer/ThumbnailInteractor.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewer/ThumbnailInteractor.h	Tue May 21 13:25:58 2019 +0200
@@ -29,7 +29,7 @@
 
   class SimpleViewerApplication;
 
-  class ThumbnailInteractor : public IWorldSceneInteractor
+  class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
   {
   private:
     SimpleViewerApplication&  application_;
@@ -39,36 +39,36 @@
     {
     }
 
-    virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                        const ViewportGeometry& view,
-                                                        MouseButton button,
-                                                        KeyboardModifiers modifiers,
-                                                        int viewportX,
-                                                        int viewportY,
-                                                        double x,
-                                                        double y,
-                                                        IStatusBar* statusBar,
-                                                        const std::vector<Touch>& displayTouches);
+    virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                    const Deprecated::ViewportGeometry& view,
+                                                                    MouseButton button,
+                                                                    KeyboardModifiers modifiers,
+                                                                    int viewportX,
+                                                                    int viewportY,
+                                                                    double x,
+                                                                    double y,
+                                                                    Deprecated::IStatusBar* statusBar,
+                                                                    const std::vector<Deprecated::Touch>& displayTouches);
 
     virtual void MouseOver(CairoContext& context,
-                           WorldSceneWidget& widget,
-                           const ViewportGeometry& view,
+                           Deprecated::WorldSceneWidget& widget,
+                           const Deprecated::ViewportGeometry& view,
                            double x,
                            double y,
-                           IStatusBar* statusBar)
+                           Deprecated::IStatusBar* statusBar)
     {}
 
-    virtual void MouseWheel(WorldSceneWidget& widget,
+    virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
                             MouseWheelDirection direction,
                             KeyboardModifiers modifiers,
-                            IStatusBar* statusBar)
+                            Deprecated::IStatusBar* statusBar)
     {}
 
-    virtual void KeyPressed(WorldSceneWidget& widget,
+    virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
                             KeyboardKeys key,
                             char keyChar,
                             KeyboardModifiers modifiers,
-                            IStatusBar* statusBar)
+                            Deprecated::IStatusBar* statusBar)
     {}
 
   };
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Tue May 21 13:25:58 2019 +0200
@@ -47,7 +47,7 @@
       public IObserver
     {
     private:
-      class ThumbnailInteractor : public IWorldSceneInteractor
+      class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
       {
       private:
         SimpleViewerApplication&  application_;
@@ -58,16 +58,16 @@
         {
         }
 
-        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                            const ViewportGeometry& view,
+        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                            const Deprecated::ViewportGeometry& view,
                                                             MouseButton button,
                                                             KeyboardModifiers modifiers,
                                                             int viewportX,
                                                             int viewportY,
                                                             double x,
                                                             double y,
-                                                            IStatusBar* statusBar,
-                                                            const std::vector<Touch>& displayTouches)
+                                                            Deprecated::IStatusBar* statusBar,
+                                                            const std::vector<Deprecated::Touch>& displayTouches)
         {
           if (button == MouseButton_Left)
           {
@@ -79,31 +79,31 @@
         }
 
         virtual void MouseOver(CairoContext& context,
-                               WorldSceneWidget& widget,
-                               const ViewportGeometry& view,
+                               Deprecated::WorldSceneWidget& widget,
+                               const Deprecated::ViewportGeometry& view,
                                double x,
                                double y,
-                               IStatusBar* statusBar)
+                               Deprecated::IStatusBar* statusBar)
         {
         }
 
-        virtual void MouseWheel(WorldSceneWidget& widget,
+        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
                                 MouseWheelDirection direction,
                                 KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
+                                Deprecated::IStatusBar* statusBar)
         {
         }
 
-        virtual void KeyPressed(WorldSceneWidget& widget,
+        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
                                 KeyboardKeys key,
                                 char keyChar,
                                 KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
+                                Deprecated::IStatusBar* statusBar)
         {
         }
       };
 
-      class MainWidgetInteractor : public IWorldSceneInteractor
+      class MainWidgetInteractor : public Deprecated::IWorldSceneInteractor
       {
       private:
         SimpleViewerApplication&  application_;
@@ -114,27 +114,27 @@
         {
         }
         
-        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                            const ViewportGeometry& view,
+        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                            const Deprecated::ViewportGeometry& view,
                                                             MouseButton button,
                                                             KeyboardModifiers modifiers,
                                                             int viewportX,
                                                             int viewportY,
                                                             double x,
                                                             double y,
-                                                            IStatusBar* statusBar,
-                                                            const std::vector<Touch>& displayTouches)
+                                                            Deprecated::IStatusBar* statusBar,
+                                                            const std::vector<Deprecated::Touch>& displayTouches)
         {
           if (button == MouseButton_Left)
           {
             if (application_.currentTool_ == Tool_LineMeasure)
             {
-              return new LineMeasureTracker(statusBar, dynamic_cast<SliceViewerWidget&>(widget).GetSlice(),
+              return new Deprecated::LineMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
                                             x, y, 255, 0, 0, application_.GetFont());
             }
             else if (application_.currentTool_ == Tool_CircleMeasure)
             {
-              return new CircleMeasureTracker(statusBar, dynamic_cast<SliceViewerWidget&>(widget).GetSlice(),
+              return new Deprecated::CircleMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
                                               x, y, 255, 0, 0, application_.GetFont());
             }
           }
@@ -142,15 +142,15 @@
         }
 
         virtual void MouseOver(CairoContext& context,
-                               WorldSceneWidget& widget,
-                               const ViewportGeometry& view,
+                               Deprecated::WorldSceneWidget& widget,
+                               const Deprecated::ViewportGeometry& view,
                                double x,
                                double y,
-                               IStatusBar* statusBar)
+                               Deprecated::IStatusBar* statusBar)
         {
           if (statusBar != NULL)
           {
-            Vector p = dynamic_cast<SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+            Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
             
             char buf[64];
             sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
@@ -159,18 +159,18 @@
           }
         }
 
-        virtual void MouseWheel(WorldSceneWidget& widget,
+        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
                                 MouseWheelDirection direction,
                                 KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
+                                Deprecated::IStatusBar* statusBar)
         {
         }
 
-        virtual void KeyPressed(WorldSceneWidget& widget,
+        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
                                 KeyboardKeys key,
                                 char keyChar,
                                 KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
+                                Deprecated::IStatusBar* statusBar)
         {
           switch (keyChar)
           {
@@ -241,19 +241,19 @@
       Tool                                 currentTool_;
       std::auto_ptr<MainWidgetInteractor>  mainWidgetInteractor_;
       std::auto_ptr<ThumbnailInteractor>   thumbnailInteractor_;
-      LayoutWidget*                        mainLayout_;
-      LayoutWidget*                        thumbnailsLayout_;
-      std::vector<SliceViewerWidget*>      thumbnails_;
+      Deprecated::LayoutWidget*                        mainLayout_;
+      Deprecated::LayoutWidget*                        thumbnailsLayout_;
+      std::vector<Deprecated::SliceViewerWidget*>      thumbnails_;
 
       std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
       std::map<std::string, Json::Value> seriesTags_;
 
       unsigned int                         currentInstanceIndex_;
-      OrthancStone::WidgetViewport*        wasmViewport1_;
-      OrthancStone::WidgetViewport*        wasmViewport2_;
+      Deprecated::WidgetViewport*        wasmViewport1_;
+      Deprecated::WidgetViewport*        wasmViewport2_;
 
-      IStatusBar*                          statusBar_;
-      std::auto_ptr<SmartLoader>           smartLoader_;
+      Deprecated::IStatusBar*                          statusBar_;
+      std::auto_ptr<Deprecated::SmartLoader>           smartLoader_;
 
       Orthanc::Font                        font_;
 
@@ -282,7 +282,7 @@
       }
 
       virtual void Initialize(StoneApplicationContext* context,
-                              IStatusBar& statusBar,
+                              Deprecated::IStatusBar& statusBar,
                               const boost::program_options::variables_map& parameters)
       {
         using namespace OrthancStone;
@@ -291,19 +291,19 @@
         statusBar_ = &statusBar;
 
         {// initialize viewports and layout
-          mainLayout_ = new LayoutWidget("main-layout");
+          mainLayout_ = new Deprecated::LayoutWidget("main-layout");
           mainLayout_->SetPadding(10);
           mainLayout_->SetBackgroundCleared(true);
           mainLayout_->SetBackgroundColor(0, 0, 0);
           mainLayout_->SetHorizontal();
 
-          thumbnailsLayout_ = new LayoutWidget("thumbnail-layout");
+          thumbnailsLayout_ = new Deprecated::LayoutWidget("thumbnail-layout");
           thumbnailsLayout_->SetPadding(10);
           thumbnailsLayout_->SetBackgroundCleared(true);
           thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
           thumbnailsLayout_->SetVertical();
 
-          mainWidget_ = new SliceViewerWidget(GetBroker(), "main-viewport");
+          mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-viewport");
           //mainWidget_->RegisterObserver(*this);
 
           // hierarchy
@@ -311,7 +311,7 @@
           mainLayout_->AddWidget(mainWidget_);
 
           // sources
-          smartLoader_.reset(new SmartLoader(GetBroker(), context->GetOrthancApiClient()));
+          smartLoader_.reset(new Deprecated::SmartLoader(GetBroker(), context->GetOrthancApiClient()));
           smartLoader_->SetImageQuality(SliceImageQuality_FullPam);
 
           mainLayout_->SetTransmitMouseOver(true);
@@ -329,7 +329,7 @@
           LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
           context->GetOrthancApiClient().GetJsonAsync(
             "/studies",
-            new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>
+            new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
             (*this, &SimpleViewerApplication::OnStudyListReceived));
         }
         else
@@ -338,7 +338,7 @@
         }
       }
 
-      void OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
+      void OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
       {
         const Json::Value& response = message.GetJson();
 
@@ -349,7 +349,7 @@
         }
       }
       
-      void OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
+      void OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
       {
         const Json::Value& response = message.GetJson();
 
@@ -359,13 +359,13 @@
           {
             context_->GetOrthancApiClient().GetJsonAsync(
               "/series/" + response["Series"][(int)i].asString(),
-              new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>
+              new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
               (*this, &SimpleViewerApplication::OnSeriesReceived));
           }
         }
       }
 
-      void OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
+      void OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
       {
         const Json::Value& response = message.GetJson();
 
@@ -387,7 +387,7 @@
           LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
 
           // if this is the first thumbnail loaded, load the first instance in the mainWidget
-          SliceViewerWidget& widget = *dynamic_cast<SliceViewerWidget*>(mainWidget_);
+          Deprecated::SliceViewerWidget& widget = *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_);
           if (widget.GetLayerCount() == 0)
           {
             smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
@@ -398,10 +398,10 @@
       void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
       {
         LOG(INFO) << "Loading thumbnail for series " << seriesId;
-        SliceViewerWidget* thumbnailWidget = new SliceViewerWidget(GetBroker(), "thumbnail-series-" + seriesId);
+        Deprecated::SliceViewerWidget* thumbnailWidget = new Deprecated::SliceViewerWidget(GetBroker(), "thumbnail-series-" + seriesId);
         thumbnails_.push_back(thumbnailWidget);
         thumbnailsLayout_->AddWidget(thumbnailWidget);
-        thumbnailWidget->RegisterObserverCallback(new Callable<SimpleViewerApplication, SliceViewerWidget::GeometryChangedMessage>(*this, &SimpleViewerApplication::OnWidgetGeometryChanged));
+        thumbnailWidget->RegisterObserverCallback(new Callable<SimpleViewerApplication, Deprecated::SliceViewerWidget::GeometryChangedMessage>(*this, &SimpleViewerApplication::OnWidgetGeometryChanged));
         smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
         thumbnailWidget->SetInteractor(*thumbnailInteractor_);
       }
@@ -410,19 +410,19 @@
       {
         LOG(INFO) << "Selecting study: " << studyId;
         context_->GetOrthancApiClient().GetJsonAsync(
-          "/studies/" + studyId, new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>
+          "/studies/" + studyId, new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
           (*this, &SimpleViewerApplication::OnStudyReceived));
       }
 
-      void OnWidgetGeometryChanged(const SliceViewerWidget::GeometryChangedMessage& message)
+      void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
       {
         // TODO: The "const_cast" could probably be replaced by "mainWidget"
-        const_cast<SliceViewerWidget&>(message.GetOrigin()).FitContent();
+        const_cast<Deprecated::SliceViewerWidget&>(message.GetOrigin()).FitContent();
       }
 
       void SelectSeriesInMainViewport(const std::string& seriesId)
       {
-        SliceViewerWidget& widget = *dynamic_cast<SliceViewerWidget*>(mainWidget_);
+        Deprecated::SliceViewerWidget& widget = *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_);
         smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
       }
 
--- a/Applications/Samples/SingleFrameApplication.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SingleFrameApplication.h	Tue May 21 13:25:58 2019 +0200
@@ -41,7 +41,7 @@
       public IObserver
     {
     private:
-      class Interactor : public IWorldSceneInteractor
+      class Interactor : public Deprecated::IWorldSceneInteractor
       {
       private:
         SingleFrameApplication&  application_;
@@ -52,30 +52,30 @@
         {
         }
         
-        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                            const ViewportGeometry& view,
-                                                            MouseButton button,
-                                                            KeyboardModifiers modifiers,
-                                                            int viewportX,
-                                                            int viewportY,
-                                                            double x,
-                                                            double y,
-                                                            IStatusBar* statusBar,
-                                                            const std::vector<Touch>& displayTouches)
+        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                        const Deprecated::ViewportGeometry& view,
+                                                                        MouseButton button,
+                                                                        KeyboardModifiers modifiers,
+                                                                        int viewportX,
+                                                                        int viewportY,
+                                                                        double x,
+                                                                        double y,
+                                                                        Deprecated::IStatusBar* statusBar,
+                                                                        const std::vector<Deprecated::Touch>& displayTouches)
         {
           return NULL;
         }
 
         virtual void MouseOver(CairoContext& context,
-                               WorldSceneWidget& widget,
-                               const ViewportGeometry& view,
+                               Deprecated::WorldSceneWidget& widget,
+                               const Deprecated::ViewportGeometry& view,
                                double x,
                                double y,
-                               IStatusBar* statusBar)
+                               Deprecated::IStatusBar* statusBar)
         {
           if (statusBar != NULL)
           {
-            Vector p = dynamic_cast<SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+            Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
             
             char buf[64];
             sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", 
@@ -84,10 +84,10 @@
           }
         }
 
-        virtual void MouseWheel(WorldSceneWidget& widget,
+        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
                                 MouseWheelDirection direction,
                                 KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
+                                Deprecated::IStatusBar* statusBar)
         {
           int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
           
@@ -106,11 +106,11 @@
           }
         }
 
-        virtual void KeyPressed(WorldSceneWidget& widget,
+        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
                                 KeyboardKeys key,
                                 char keyChar,
                                 KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
+                                Deprecated::IStatusBar* statusBar)
         {
           switch (keyChar)
           {
@@ -149,9 +149,9 @@
       }
 
 
-      SliceViewerWidget& GetMainWidget()
+      Deprecated::SliceViewerWidget& GetMainWidget()
       {
-        return *dynamic_cast<SliceViewerWidget*>(mainWidget_);
+        return *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_);
       }
       
 
@@ -184,7 +184,7 @@
       }
         
       
-      void OnMainWidgetGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
+      void OnMainWidgetGeometryReady(const Deprecated::IVolumeSlicer::GeometryReadyMessage& message)
       {
         // Once the geometry of the series is downloaded from Orthanc,
         // display its middle slice, and adapt the viewport to fit this
@@ -198,7 +198,7 @@
       }
       
       std::auto_ptr<Interactor>         mainWidgetInteractor_;
-      const DicomSeriesVolumeSlicer*    source_;
+      const Deprecated::DicomSeriesVolumeSlicer*    source_;
       unsigned int                      slice_;
 
     public:
@@ -225,7 +225,7 @@
       }
 
       virtual void Initialize(StoneApplicationContext* context,
-                              IStatusBar& statusBar,
+                              Deprecated::IStatusBar& statusBar,
                               const boost::program_options::variables_map& parameters)
       {
         using namespace OrthancStone;
@@ -243,15 +243,15 @@
         std::string instance = parameters["instance"].as<std::string>();
         int frame = parameters["frame"].as<unsigned int>();
 
-        mainWidget_ = new SliceViewerWidget(GetBroker(), "main-widget");
+        mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-widget");
 
-        std::auto_ptr<DicomSeriesVolumeSlicer> layer(new DicomSeriesVolumeSlicer(GetBroker(), context->GetOrthancApiClient()));
+        std::auto_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer(GetBroker(), context->GetOrthancApiClient()));
         source_ = layer.get();
         layer->LoadFrame(instance, frame);
-        layer->RegisterObserverCallback(new Callable<SingleFrameApplication, IVolumeSlicer::GeometryReadyMessage>(*this, &SingleFrameApplication::OnMainWidgetGeometryReady));
+        layer->RegisterObserverCallback(new Callable<SingleFrameApplication, Deprecated::IVolumeSlicer::GeometryReadyMessage>(*this, &SingleFrameApplication::OnMainWidgetGeometryReady));
         GetMainWidget().AddLayer(layer.release());
 
-        RenderStyle s;
+        Deprecated::RenderStyle s;
 
         if (parameters["smooth"].as<bool>())
         {
--- a/Applications/Samples/SingleFrameEditorApplication.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Tue May 21 13:25:58 2019 +0200
@@ -52,7 +52,7 @@
   namespace Samples
   {
     class RadiographyEditorInteractor :
-        public IWorldSceneInteractor,
+        public Deprecated::IWorldSceneInteractor,
         public IObserver
     {
     private:
@@ -97,16 +97,16 @@
       {
         maskLayer_ = maskLayer;
       }
-      virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget,
-                                                          const ViewportGeometry& view,
-                                                          MouseButton button,
-                                                          KeyboardModifiers modifiers,
-                                                          int viewportX,
-                                                          int viewportY,
-                                                          double x,
-                                                          double y,
-                                                          IStatusBar* statusBar,
-                                                          const std::vector<Touch>& displayTouches)
+      virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& worldWidget,
+                                                                      const Deprecated::ViewportGeometry& view,
+                                                                      MouseButton button,
+                                                                      KeyboardModifiers modifiers,
+                                                                      int viewportX,
+                                                                      int viewportY,
+                                                                      double x,
+                                                                      double y,
+                                                                      Deprecated::IStatusBar* statusBar,
+                                                                      const std::vector<Deprecated::Touch>& displayTouches)
       {
         RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
 
@@ -226,11 +226,11 @@
       }
 
       virtual void MouseOver(CairoContext& context,
-                             WorldSceneWidget& worldWidget,
-                             const ViewportGeometry& view,
+                             Deprecated::WorldSceneWidget& worldWidget,
+                             const Deprecated::ViewportGeometry& view,
                              double x,
                              double y,
-                             IStatusBar* statusBar)
+                             Deprecated::IStatusBar* statusBar)
       {
         RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
 
@@ -270,18 +270,18 @@
         }
       }
 
-      virtual void MouseWheel(WorldSceneWidget& widget,
+      virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
                               MouseWheelDirection direction,
                               KeyboardModifiers modifiers,
-                              IStatusBar* statusBar)
+                              Deprecated::IStatusBar* statusBar)
       {
       }
 
-      virtual void KeyPressed(WorldSceneWidget& worldWidget,
+      virtual void KeyPressed(Deprecated::WorldSceneWidget& worldWidget,
                               KeyboardKeys key,
                               char keyChar,
                               KeyboardModifiers modifiers,
-                              IStatusBar* statusBar)
+                              Deprecated::IStatusBar* statusBar)
       {
         RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
 
@@ -455,7 +455,7 @@
       }
 
       virtual void Initialize(StoneApplicationContext* context,
-                              IStatusBar& statusBar,
+                              Deprecated::IStatusBar& statusBar,
                               const boost::program_options::variables_map& parameters)
       {
         using namespace OrthancStone;
@@ -485,7 +485,7 @@
         }
 
         std::string instance = parameters["instance"].as<std::string>();
-        int frame = parameters["frame"].as<unsigned int>();
+        //int frame = parameters["frame"].as<unsigned int>();
 
         fontRegistry_.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
         
--- a/Applications/Sdl/SdlCairoSurface.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Sdl/SdlCairoSurface.cpp	Tue May 21 13:25:58 2019 +0200
@@ -74,7 +74,7 @@
   }
 
 
-  void SdlCairoSurface::Render(IViewport& viewport)
+  void SdlCairoSurface::Render(Deprecated::IViewport& viewport)
   {
     if (cairoSurface_.get() == NULL)
     {
--- a/Applications/Sdl/SdlCairoSurface.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Sdl/SdlCairoSurface.h	Tue May 21 13:25:58 2019 +0200
@@ -46,7 +46,7 @@
     void SetSize(unsigned int width,
                  unsigned int height);
 
-    void Render(IViewport& viewport);
+    void Render(Deprecated::IViewport& viewport);
   };
 }
 
--- a/Applications/Sdl/SdlEngine.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Sdl/SdlEngine.cpp	Tue May 21 13:25:58 2019 +0200
@@ -146,15 +146,15 @@
           switch (event.button.button)
           {
           case SDL_BUTTON_LEFT:
-            locker.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers, std::vector<Touch>());
+            locker.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
             break;
             
           case SDL_BUTTON_RIGHT:
-            locker.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers, std::vector<Touch>());
+            locker.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
             break;
             
           case SDL_BUTTON_MIDDLE:
-            locker.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers, std::vector<Touch>());
+            locker.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
             break;
 
           default:
@@ -163,7 +163,7 @@
         }
         else if (event.type == SDL_MOUSEMOTION)
         {
-          locker.GetCentralViewport().MouseMove(event.button.x, event.button.y, std::vector<Touch>());
+          locker.GetCentralViewport().MouseMove(event.button.x, event.button.y, std::vector<Deprecated::Touch>());
         }
         else if (event.type == SDL_MOUSEBUTTONUP)
         {
--- a/Applications/Sdl/SdlEngine.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Sdl/SdlEngine.h	Tue May 21 13:25:58 2019 +0200
@@ -49,7 +49,7 @@
               NativeStoneApplicationContext& context,
               MessageBroker& broker);
   
-    void OnViewportChanged(const IViewport::ViewportChangedMessage& message)
+    void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
     {
       viewportChanged_ = true;
     }
--- a/Applications/Sdl/SdlStoneApplicationRunner.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/Sdl/SdlStoneApplicationRunner.cpp	Tue May 21 13:25:58 2019 +0200
@@ -110,7 +110,7 @@
       NativeStoneApplicationContext::GlobalMutexLocker locker(context);
 
       locker.GetCentralViewport().RegisterObserverCallback(
-        new Callable<SdlEngine, IViewport::ViewportChangedMessage>
+        new Callable<SdlEngine, Deprecated::IViewport::ViewportChangedMessage>
         (sdl, &SdlEngine::OnViewportChanged));
 
       //context.GetCentralViewport().Register(sdl);  // (*)
--- a/Applications/StoneApplicationContext.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/StoneApplicationContext.cpp	Tue May 21 13:25:58 2019 +0200
@@ -32,11 +32,11 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
 
-    orthanc_.reset(new OrthancApiClient(broker_, *webService_, orthancBaseUrl_));
+    orthanc_.reset(new Deprecated::OrthancApiClient(broker_, *webService_, orthancBaseUrl_));
   }
 
 
-  IWebService& StoneApplicationContext::GetWebService()
+  Deprecated::IWebService& StoneApplicationContext::GetWebService()
   {
     if (webService_ == NULL)
     {
@@ -47,7 +47,7 @@
   }
 
   
-  OrthancApiClient& StoneApplicationContext::GetOrthancApiClient()
+  Deprecated::OrthancApiClient& StoneApplicationContext::GetOrthancApiClient()
   {
     if (orthanc_.get() == NULL)
     {
@@ -58,7 +58,7 @@
   }
 
   
-  void StoneApplicationContext::SetWebService(IWebService& webService)
+  void StoneApplicationContext::SetWebService(Deprecated::IWebService& webService)
   {
     webService_ = &webService;
     InitializeOrthanc();
--- a/Applications/StoneApplicationContext.h	Thu May 16 19:10:38 2019 +0200
+++ b/Applications/StoneApplicationContext.h	Tue May 21 13:25:58 2019 +0200
@@ -60,9 +60,9 @@
   {
   private:
     MessageBroker&                   broker_;
-    IWebService*                     webService_;
-    IDelayedCallExecutor*            delayedCallExecutor_;
-    std::auto_ptr<OrthancApiClient>  orthanc_;
+    Deprecated::IWebService*         webService_;
+    Deprecated::IDelayedCallExecutor*            delayedCallExecutor_;
+    std::auto_ptr<Deprecated::OrthancApiClient>  orthanc_;
     std::string                      orthancBaseUrl_;
 
     void InitializeOrthanc();
@@ -89,20 +89,20 @@
       return webService_ != NULL;
     }
 
-    IWebService& GetWebService();
+    Deprecated::IWebService& GetWebService();
 
-    OrthancApiClient& GetOrthancApiClient();
+    Deprecated::OrthancApiClient& GetOrthancApiClient();
 
-    void SetWebService(IWebService& webService);
+    void SetWebService(Deprecated::IWebService& webService);
 
     void SetOrthancBaseUrl(const std::string& baseUrl);
 
-    void SetDelayedCallExecutor(IDelayedCallExecutor& delayedCallExecutor)
+    void SetDelayedCallExecutor(Deprecated::IDelayedCallExecutor& delayedCallExecutor)
     {
       delayedCallExecutor_ = &delayedCallExecutor;
     }
 
-    IDelayedCallExecutor& GetDelayedCallExecutor()
+    Deprecated::IDelayedCallExecutor& GetDelayedCallExecutor()
     {
       return *delayedCallExecutor_;
     }
--- a/Framework/Fonts/FontRenderer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Fonts/FontRenderer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -101,7 +101,9 @@
       
       const FT_Byte* data = reinterpret_cast<const FT_Byte*>(fontContent_.c_str());
 
-      CheckError(FT_New_Memory_Face(library_, data, fontContent_.size(), 0, &face_));
+      CheckError(FT_New_Memory_Face(
+        library_, data, static_cast<FT_Long>(fontContent_.size()), 0, &face_));
+
       CheckError(FT_Set_Char_Size(face_,         // handle to face object  
                                   0,             // char_width in 1/64th of points  
                                   fontSize * 64, // char_height in 1/64th of points 
--- a/Framework/Fonts/GlyphTextureAlphabet.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Fonts/GlyphTextureAlphabet.cpp	Tue May 21 13:25:58 2019 +0200
@@ -89,7 +89,7 @@
       column_(0),
       row_(0)
     {
-      int c = boost::math::iround<int>(sqrt(static_cast<float>(countGlyphs)));
+      int c = boost::math::iround<float>(sqrt(static_cast<float>(countGlyphs)));
 
       if (c <= 0)
       {
@@ -239,9 +239,9 @@
     sourceAlphabet.GetAlphabet().Apply(size);
 
     TextureGenerator generator(alphabet_,
-                               sourceAlphabet.GetAlphabet().GetSize(),
-                               size.GetMaxWidth(),
-                               size.GetMaxHeight());
+      static_cast<unsigned int>(sourceAlphabet.GetAlphabet().GetSize()),
+      size.GetMaxWidth(),
+      size.GetMaxHeight());
     sourceAlphabet.GetAlphabet().Apply(generator);
 
     texture_.reset(generator.ReleaseTexture());
--- a/Framework/Fonts/OpenGLTextCoordinates.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Fonts/OpenGLTextCoordinates.cpp	Tue May 21 13:25:58 2019 +0200
@@ -35,8 +35,8 @@
                                       const Orthanc::IDynamicObject* payload)
     {
       // Rendering coordinates
-      float rx1 = x - box_.GetLeft();
-      float ry1 = y - box_.GetTop();
+      float rx1 = static_cast<float>(x - box_.GetLeft());
+      float ry1 = static_cast<float>(y - box_.GetTop());
       float rx2 = rx1 + static_cast<float>(width);
       float ry2 = ry1 + static_cast<float>(height);
 
@@ -81,8 +81,8 @@
     OpenGLTextCoordinates::OpenGLTextCoordinates(const GlyphTextureAlphabet& alphabet,
                                                  const std::string& utf8) :
       box_(alphabet.GetAlphabet(), utf8),
-      textureWidth_(alphabet.GetTextureWidth()),
-      textureHeight_(alphabet.GetTextureHeight())
+      textureWidth_(static_cast<float>(alphabet.GetTextureWidth())),
+      textureHeight_(static_cast<float>(alphabet.GetTextureHeight()))
     {
       if (textureWidth_ <= 0 ||
           textureHeight_ <= 0)
--- a/Framework/Layers/CircleMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/CircleMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,10 +24,10 @@
 #include <stdio.h>
 #include <boost/math/constants/constants.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   CircleMeasureTracker::CircleMeasureTracker(IStatusBar* statusBar,
-                                             const CoordinateSystem3D& slice,
+                                             const OrthancStone::CoordinateSystem3D& slice,
                                              double x, 
                                              double y,
                                              uint8_t red,
@@ -48,14 +48,14 @@
   }
     
 
-  void CircleMeasureTracker::Render(CairoContext& context,
+  void CircleMeasureTracker::Render(OrthancStone::CairoContext& context,
                                     double zoom)
   {
     double x = (x1_ + x2_) / 2.0;
     double y = (y1_ + y2_) / 2.0;
 
-    Vector tmp;
-    LinearAlgebra::AssignVector(tmp, x2_ - x1_, y2_ - y1_);
+    OrthancStone::Vector tmp;
+    OrthancStone::LinearAlgebra::AssignVector(tmp, x2_ - x1_, y2_ - y1_);
     double r = boost::numeric::ublas::norm_2(tmp) / 2.0;
 
     context.SetSourceColor(color_[0], color_[1], color_[2]);
@@ -69,14 +69,14 @@
     cairo_stroke(cr);
     cairo_restore(cr);
 
-    context.DrawText(font_, FormatRadius(), x, y, BitmapAnchor_Center);
+    context.DrawText(font_, FormatRadius(), x, y, OrthancStone::BitmapAnchor_Center);
   }
     
 
   double CircleMeasureTracker::GetRadius() const  // In millimeters
   {
-    Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
-    Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
+    OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
+    OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
     return boost::numeric::ublas::norm_2(b - a) / 2.0;
   }
 
--- a/Framework/Layers/CircleMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/CircleMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -28,13 +28,13 @@
 
 #include <Core/Images/Font.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class CircleMeasureTracker : public IWorldSceneMouseTracker
   {
   private:
     IStatusBar*           statusBar_;
-    CoordinateSystem3D    slice_;
+    OrthancStone::CoordinateSystem3D    slice_;
     double                x1_;
     double                y1_;
     double                x2_;
@@ -44,7 +44,7 @@
 
   public:
     CircleMeasureTracker(IStatusBar* statusBar,
-                         const CoordinateSystem3D& slice,
+                         const OrthancStone::CoordinateSystem3D& slice,
                          double x, 
                          double y,
                          uint8_t red,
@@ -57,7 +57,7 @@
       return true;
     }
 
-    virtual void Render(CairoContext& context,
+    virtual void Render(OrthancStone::CairoContext& context,
                         double zoom);
     
     double GetRadius() const;  // In millimeters
--- a/Framework/Layers/ColorFrameRenderer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/ColorFrameRenderer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -25,11 +25,12 @@
 #include <Core/Images/Image.h>
 #include <Core/Images/ImageProcessing.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style)
+  OrthancStone::CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style)
   {
-    std::auto_ptr<CairoSurface> display(new CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
+    std::auto_ptr<OrthancStone::CairoSurface> display
+      (new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
 
     Orthanc::ImageAccessor target;
     display->GetWriteableAccessor(target);
@@ -41,7 +42,7 @@
 
 
   ColorFrameRenderer::ColorFrameRenderer(const Orthanc::ImageAccessor& frame,
-                                         const CoordinateSystem3D& framePlane,
+                                         const OrthancStone::CoordinateSystem3D& framePlane,
                                          double pixelSpacingX,
                                          double pixelSpacingY,
                                          bool isFullQuality) :
--- a/Framework/Layers/ColorFrameRenderer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/ColorFrameRenderer.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "FrameRenderer.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class ColorFrameRenderer : public FrameRenderer
   {
@@ -31,11 +31,11 @@
     std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In RGB24
 
   protected:
-    virtual CairoSurface* GenerateDisplay(const RenderStyle& style);
+    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
 
   public:
     ColorFrameRenderer(const Orthanc::ImageAccessor& frame,
-                       const CoordinateSystem3D& framePlane,
+                       const OrthancStone::CoordinateSystem3D& framePlane,
                        double pixelSpacingX,
                        double pixelSpacingY,
                        bool isFullQuality);
--- a/Framework/Layers/DicomSeriesVolumeSlicer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/DicomSeriesVolumeSlicer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -29,7 +29,7 @@
 
 #include <boost/lexical_cast.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
 
   void DicomSeriesVolumeSlicer::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
@@ -63,8 +63,8 @@
 
     virtual ILayerRenderer* CreateRenderer() const
     {
-      bool isFull = (message_.GetEffectiveQuality() == SliceImageQuality_FullPng ||
-                     message_.GetEffectiveQuality() == SliceImageQuality_FullPam);
+      bool isFull = (message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPng ||
+                     message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPam);
 
       return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull);
     }
@@ -87,26 +87,27 @@
   }
 
 
-  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(MessageBroker& broker, OrthancApiClient& orthanc) :
+  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
+                                                   OrthancApiClient& orthanc) :
     IVolumeSlicer(broker),
     IObserver(broker),
     loader_(broker, orthanc),
-    quality_(SliceImageQuality_FullPng)
+    quality_(OrthancStone::SliceImageQuality_FullPng)
   {
     loader_.RegisterObserverCallback(
-      new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage>
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage>
         (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady));
 
     loader_.RegisterObserverCallback(
-      new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage>
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage>
       (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError));
 
     loader_.RegisterObserverCallback(
-      new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage>
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage>
         (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady));
 
     loader_.RegisterObserverCallback(
-      new Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage>
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage>
       (*this, &DicomSeriesVolumeSlicer::OnSliceImageError));
   }
 
@@ -130,8 +131,8 @@
   }
 
 
-  bool DicomSeriesVolumeSlicer::GetExtent(std::vector<Vector>& points,
-                                          const CoordinateSystem3D& viewportSlice)
+  bool DicomSeriesVolumeSlicer::GetExtent(std::vector<OrthancStone::Vector>& points,
+                                          const OrthancStone::CoordinateSystem3D& viewportSlice)
   {
     size_t index;
 
@@ -148,7 +149,7 @@
   }
 
   
-  void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice)
+  void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
   {
     size_t index;
 
--- a/Framework/Layers/DicomSeriesVolumeSlicer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/DicomSeriesVolumeSlicer.h	Tue May 21 13:25:58 2019 +0200
@@ -26,31 +26,31 @@
 #include "../Toolbox/OrthancSlicesLoader.h"
 #include "../Toolbox/OrthancApiClient.h"
 
-namespace OrthancStone
+namespace Deprecated
 {  
   // 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 IVolumeSlicer,
-    public IObserver
+    public OrthancStone::IObserver
     //private OrthancSlicesLoader::ISliceLoaderObserver
   {
   public:
     // TODO: Add "frame" and "instanceId"
-    class FrameReadyMessage : public OriginMessage<DicomSeriesVolumeSlicer>
+    class FrameReadyMessage : public OrthancStone::OriginMessage<DicomSeriesVolumeSlicer>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
       const Orthanc::ImageAccessor&  frame_;
-      SliceImageQuality              imageQuality_;
+      OrthancStone::SliceImageQuality              imageQuality_;
       const Slice&                   slice_;
 
     public:
       FrameReadyMessage(DicomSeriesVolumeSlicer& origin,
                         const Orthanc::ImageAccessor& frame,
-                        SliceImageQuality imageQuality,
+                        OrthancStone::SliceImageQuality imageQuality,
                         const Slice& slice) :
         OriginMessage(origin),
         frame_(frame),
@@ -64,7 +64,7 @@
         return frame_;
       }
 
-      SliceImageQuality GetImageQuality() const
+      OrthancStone::SliceImageQuality GetImageQuality() const
       {
         return imageQuality_;
       }
@@ -80,10 +80,11 @@
     class RendererFactory;
     
     OrthancSlicesLoader  loader_;
-    SliceImageQuality    quality_;
+    OrthancStone::SliceImageQuality    quality_;
 
   public:
-    DicomSeriesVolumeSlicer(MessageBroker& broker, OrthancApiClient& orthanc);
+    DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
+                            OrthancApiClient& orthanc);
 
     void LoadSeries(const std::string& seriesId);
 
@@ -92,12 +93,12 @@
     void LoadFrame(const std::string& instanceId,
                    unsigned int frame);
 
-    void SetImageQuality(SliceImageQuality quality)
+    void SetImageQuality(OrthancStone::SliceImageQuality quality)
     {
       quality_ = quality;
     }
 
-    SliceImageQuality GetImageQuality() const
+    OrthancStone::SliceImageQuality GetImageQuality() const
     {
       return quality_;
     }
@@ -112,10 +113,10 @@
       return loader_.GetSlice(slice);
     }
 
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice);
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice);
 
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice);
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice);
 
 protected:
     void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message);
--- a/Framework/Layers/DicomStructureSetSlicer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/DicomStructureSetSlicer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -21,7 +21,7 @@
 
 #include "DicomStructureSetSlicer.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class DicomStructureSetSlicer::Renderer : public ILayerRenderer
   {
@@ -34,11 +34,11 @@
       uint8_t                                                      green_;
       uint8_t                                                      blue_;
       std::string                                                  name_;
-      std::vector< std::vector<DicomStructureSet::PolygonPoint> >  polygons_;
+      std::vector< std::vector<OrthancStone::DicomStructureSet::PolygonPoint> >  polygons_;
 
     public:
-      Structure(DicomStructureSet& structureSet,
-                const CoordinateSystem3D& plane,
+      Structure(OrthancStone::DicomStructureSet& structureSet,
+                const OrthancStone::CoordinateSystem3D& plane,
                 size_t index) :
         name_(structureSet.GetStructureName(index))
       {
@@ -46,7 +46,7 @@
         visible_ = structureSet.ProjectStructure(polygons_, index, plane);
       }
 
-      void Render(CairoContext& context)
+      void Render(OrthancStone::CairoContext& context)
       {
         if (visible_)
         {
@@ -72,12 +72,12 @@
 
     typedef std::list<Structure*>  Structures;
     
-    CoordinateSystem3D  plane_;
+    OrthancStone::CoordinateSystem3D  plane_;
     Structures          structures_;
     
   public:
-    Renderer(DicomStructureSet& structureSet,
-             const CoordinateSystem3D& plane) :
+    Renderer(OrthancStone::DicomStructureSet& structureSet,
+             const OrthancStone::CoordinateSystem3D& plane) :
       plane_(plane)
     {
       for (size_t k = 0; k < structureSet.GetStructureCount(); k++)
@@ -95,7 +95,7 @@
       }
     }
 
-    virtual bool RenderLayer(CairoContext& context,
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view)
     {
       cairo_set_line_width(context.GetObject(), 2.0f / view.GetZoom());
@@ -110,7 +110,7 @@
       return true;
     }
 
-    virtual const CoordinateSystem3D& GetLayerPlane()
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
     {
       return plane_;
     }
@@ -129,12 +129,12 @@
   class DicomStructureSetSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory
   {
   private:
-    DicomStructureSet&         structureSet_;
-    const CoordinateSystem3D&  plane_;
+    OrthancStone::DicomStructureSet&         structureSet_;
+    const OrthancStone::CoordinateSystem3D&  plane_;
 
   public:
-    RendererFactory(DicomStructureSet& structureSet,
-                    const CoordinateSystem3D&  plane) :
+    RendererFactory(OrthancStone::DicomStructureSet& structureSet,
+                    const OrthancStone::CoordinateSystem3D&  plane) :
       structureSet_(structureSet),
       plane_(plane)
     {
@@ -147,19 +147,19 @@
   };
   
 
-  DicomStructureSetSlicer::DicomStructureSetSlicer(MessageBroker& broker,
+  DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
                                                    StructureSetLoader& loader) :
     IVolumeSlicer(broker),
     IObserver(broker),
     loader_(loader)
   {
     loader_.RegisterObserverCallback(
-      new Callable<DicomStructureSetSlicer, StructureSetLoader::ContentChangedMessage>
+      new OrthancStone::Callable<DicomStructureSetSlicer, StructureSetLoader::ContentChangedMessage>
       (*this, &DicomStructureSetSlicer::OnStructureSetLoaded));
   }
 
 
-  void DicomStructureSetSlicer::ScheduleLayerCreation(const CoordinateSystem3D& viewportPlane)
+  void DicomStructureSetSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane)
   {
     if (loader_.HasStructureSet())
     {
--- a/Framework/Layers/DicomStructureSetSlicer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/DicomStructureSetSlicer.h	Tue May 21 13:25:58 2019 +0200
@@ -24,11 +24,11 @@
 #include "IVolumeSlicer.h"
 #include "../Volumes/StructureSetLoader.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class DicomStructureSetSlicer :
     public IVolumeSlicer,
-    public IObserver
+    public OrthancStone::IObserver
   {
   private:
     class Renderer;
@@ -42,15 +42,15 @@
     }
 
   public:
-    DicomStructureSetSlicer(MessageBroker& broker,
+    DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
                             StructureSetLoader& loader);
 
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportPlane)
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportPlane)
     {
       return false;
     }
 
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportPlane);
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane);
   };
 }
--- a/Framework/Layers/FrameRenderer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/FrameRenderer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -26,9 +26,9 @@
 
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  FrameRenderer::FrameRenderer(const CoordinateSystem3D& framePlane,
+  FrameRenderer::FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane,
                                double pixelSpacingX,
                                double pixelSpacingY,
                                bool isFullQuality) :
@@ -40,7 +40,7 @@
   }
 
 
-  bool FrameRenderer::RenderLayer(CairoContext& context,
+  bool FrameRenderer::RenderLayer(OrthancStone::CairoContext& context,
                                   const ViewportGeometry& view)
   {    
     if (!style_.visible_)
@@ -70,11 +70,11 @@
 
     switch (style_.interpolation_)
     {
-      case ImageInterpolation_Nearest:
+      case OrthancStone::ImageInterpolation_Nearest:
         cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
         break;
 
-      case ImageInterpolation_Bilinear:
+      case OrthancStone::ImageInterpolation_Bilinear:
         cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR);
         break;
 
@@ -118,7 +118,7 @@
 
 
   ILayerRenderer* FrameRenderer::CreateRenderer(const Orthanc::ImageAccessor& frame,
-                                                const Slice& framePlane,
+                                                const Deprecated::Slice& framePlane,
                                                 bool isFullQuality)
   {
     if (frame.GetFormat() == Orthanc::PixelFormat_RGB24)
--- a/Framework/Layers/FrameRenderer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/FrameRenderer.h	Tue May 21 13:25:58 2019 +0200
@@ -25,31 +25,31 @@
 
 #include "../Toolbox/Slice.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class FrameRenderer : public ILayerRenderer
   {
   private:
-    CoordinateSystem3D            framePlane_;
+    OrthancStone::CoordinateSystem3D            framePlane_;
     double                        pixelSpacingX_;
     double                        pixelSpacingY_;
     RenderStyle                   style_;
     bool                          isFullQuality_;
-    std::auto_ptr<CairoSurface>   display_;
+    std::auto_ptr<OrthancStone::CairoSurface>   display_;
 
   protected:
-    virtual CairoSurface* GenerateDisplay(const RenderStyle& style) = 0;
+    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style) = 0;
 
   public:
-    FrameRenderer(const CoordinateSystem3D& framePlane,
+    FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane,
                   double pixelSpacingX,
                   double pixelSpacingY,
                   bool isFullQuality);
 
-    virtual bool RenderLayer(CairoContext& context,
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view);
 
-    virtual const CoordinateSystem3D& GetLayerPlane()
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
     {
       return framePlane_;
     }
@@ -63,7 +63,7 @@
 
     // TODO: Avoid cloning the "frame"
     static ILayerRenderer* CreateRenderer(const Orthanc::ImageAccessor& frame,
-                                          const Slice& framePlane,
+                                          const Deprecated::Slice& framePlane,
                                           bool isFullQuality);
   };
 }
--- a/Framework/Layers/GrayscaleFrameRenderer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/GrayscaleFrameRenderer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,13 +24,13 @@
 #include <Core/Images/Image.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  CairoSurface* GrayscaleFrameRenderer::GenerateDisplay(const RenderStyle& style)
+  OrthancStone::CairoSurface* GrayscaleFrameRenderer::GenerateDisplay(const RenderStyle& style)
   {
     assert(frame_->GetFormat() == Orthanc::PixelFormat_Float32);
 
-    std::auto_ptr<CairoSurface> result;
+    std::auto_ptr<OrthancStone::CairoSurface> result;
 
     float windowCenter, windowWidth;
     style.ComputeWindowing(windowCenter, windowWidth,
@@ -41,7 +41,7 @@
 
     //LOG(INFO) << "Window: " << x0 << " => " << x1;
 
-    result.reset(new CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
+    result.reset(new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
 
     const uint8_t* lut = NULL;
     if (style.applyLut_)
@@ -114,8 +114,8 @@
 
 
   GrayscaleFrameRenderer::GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame,
-                                                 const DicomFrameConverter& converter,
-                                                 const CoordinateSystem3D& framePlane,
+                                                 const Deprecated::DicomFrameConverter& converter,
+                                                 const OrthancStone::CoordinateSystem3D& framePlane,
                                                  double pixelSpacingX,
                                                  double pixelSpacingY,
                                                  bool isFullQuality) :
--- a/Framework/Layers/GrayscaleFrameRenderer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/GrayscaleFrameRenderer.h	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include "FrameRenderer.h"
 #include "../Toolbox/DicomFrameConverter.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class GrayscaleFrameRenderer : public FrameRenderer
   {
@@ -35,12 +35,12 @@
     Orthanc::PhotometricInterpretation      photometric_;
 
   protected:
-    virtual CairoSurface* GenerateDisplay(const RenderStyle& style);
+    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
 
   public:
     GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame,
-                           const DicomFrameConverter& converter,
-                           const CoordinateSystem3D& framePlane,
+                           const Deprecated::DicomFrameConverter& converter,
+                           const OrthancStone::CoordinateSystem3D& framePlane,
                            double pixelSpacingX,
                            double pixelSpacingY,
                            bool isFullQuality);
--- a/Framework/Layers/ILayerRenderer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/ILayerRenderer.h	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 #include "../Toolbox/ViewportGeometry.h"
 #include "RenderStyle.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class ILayerRenderer : public boost::noncopyable
   {
@@ -35,12 +35,12 @@
     {
     }
     
-    virtual bool RenderLayer(CairoContext& context,
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view) = 0;
 
     virtual void SetLayerStyle(const RenderStyle& style) = 0;
 
-    virtual const CoordinateSystem3D& GetLayerPlane() = 0;
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() = 0;
     
     virtual bool IsFullQuality() = 0;
   };
--- a/Framework/Layers/IVolumeSlicer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/IVolumeSlicer.h	Tue May 21 13:25:58 2019 +0200
@@ -28,38 +28,38 @@
 #include "Core/Images/Image.h"
 #include <boost/shared_ptr.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  class IVolumeSlicer : public IObservable
+  class IVolumeSlicer : public OrthancStone::IObservable
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeSlicer);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeSlicer);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeSlicer);
 
-    class SliceContentChangedMessage : public OriginMessage<IVolumeSlicer>
+    class SliceContentChangedMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      const Slice& slice_;
+      const Deprecated::Slice& slice_;
 
     public:
       SliceContentChangedMessage(IVolumeSlicer& origin,
-                                 const Slice& slice) :
+                                 const Deprecated::Slice& slice) :
         OriginMessage(origin),
         slice_(slice)
       {
       }
 
-      const Slice& GetSlice() const
+      const Deprecated::Slice& GetSlice() const
       {
         return slice_;
       }
     };
     
 
-    class LayerReadyMessage : public OriginMessage<IVolumeSlicer>
+    class LayerReadyMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
@@ -76,12 +76,12 @@
     
     private:
       const IRendererFactory&    factory_;
-      const CoordinateSystem3D&  slice_;
+      const OrthancStone::CoordinateSystem3D&  slice_;
 
     public:
       LayerReadyMessage(IVolumeSlicer& origin,
                         const IRendererFactory& rendererFactory,
-                        const CoordinateSystem3D& slice) :
+                        const OrthancStone::CoordinateSystem3D& slice) :
         OriginMessage(origin),
         factory_(rendererFactory),
         slice_(slice)
@@ -93,36 +93,36 @@
         return factory_.CreateRenderer();
       }
 
-      const CoordinateSystem3D& GetSlice() const
+      const OrthancStone::CoordinateSystem3D& GetSlice() const
       {
         return slice_;
       }
     };
 
 
-    class LayerErrorMessage : public OriginMessage<IVolumeSlicer>
+    class LayerErrorMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      const CoordinateSystem3D&  slice_;
+      const OrthancStone::CoordinateSystem3D&  slice_;
 
     public:
       LayerErrorMessage(IVolumeSlicer& origin,
-                        const CoordinateSystem3D& slice) :
+                        const OrthancStone::CoordinateSystem3D& slice) :
         OriginMessage(origin),
         slice_(slice)
       {
       }
 
-      const CoordinateSystem3D& GetSlice() const
+      const OrthancStone::CoordinateSystem3D& GetSlice() const
       {
         return slice_;
       }
     };
 
 
-    IVolumeSlicer(MessageBroker& broker) :
+    IVolumeSlicer(OrthancStone::MessageBroker& broker) :
       IObservable(broker)
     {
     }
@@ -131,9 +131,9 @@
     {
     }
 
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice) = 0;
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice) = 0;
 
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) = 0;
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) = 0;
   };
 }
--- a/Framework/Layers/LineLayerRenderer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/LineLayerRenderer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -21,13 +21,13 @@
 
 #include "LineLayerRenderer.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   LineLayerRenderer::LineLayerRenderer(double x1,
                                        double y1,
                                        double x2,
                                        double y2,
-                                       const CoordinateSystem3D& plane) : 
+                                       const OrthancStone::CoordinateSystem3D& plane) : 
     x1_(x1),
     y1_(y1),
     x2_(x2),
@@ -39,7 +39,7 @@
   }
 
 
-  bool LineLayerRenderer::RenderLayer(CairoContext& context,
+  bool LineLayerRenderer::RenderLayer(OrthancStone::CairoContext& context,
                                       const ViewportGeometry& view)
   {
     if (visible_)
--- a/Framework/Layers/LineLayerRenderer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/LineLayerRenderer.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "ILayerRenderer.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class LineLayerRenderer : public ILayerRenderer
   {
@@ -32,7 +32,7 @@
     double              y1_;
     double              x2_;
     double              y2_;
-    CoordinateSystem3D  plane_;
+    OrthancStone::CoordinateSystem3D  plane_;
     bool                visible_;
     uint8_t             color_[3];
 
@@ -41,14 +41,14 @@
                       double y1,
                       double x2,
                       double y2,
-                      const CoordinateSystem3D& plane);
+                      const OrthancStone::CoordinateSystem3D& plane);
 
-    virtual bool RenderLayer(CairoContext& context,
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view);
 
     virtual void SetLayerStyle(const RenderStyle& style);
 
-    virtual const CoordinateSystem3D& GetLayerPlane()
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
     {
       return plane_;
     }
--- a/Framework/Layers/LineMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/LineMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -23,10 +23,10 @@
 
 #include <stdio.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   LineMeasureTracker::LineMeasureTracker(IStatusBar* statusBar,
-                                         const CoordinateSystem3D& slice,
+                                         const OrthancStone::CoordinateSystem3D& slice,
                                          double x, 
                                          double y,
                                          uint8_t red,
@@ -47,7 +47,7 @@
   }
     
 
-  void LineMeasureTracker::Render(CairoContext& context,
+  void LineMeasureTracker::Render(OrthancStone::CairoContext& context,
                                   double zoom)
   {
     context.SetSourceColor(color_[0], color_[1], color_[2]);
@@ -60,19 +60,19 @@
 
     if (y2_ - y1_ < 0)
     {
-      context.DrawText(font_, FormatLength(), x2_, y2_ - 5, BitmapAnchor_BottomCenter);
+      context.DrawText(font_, FormatLength(), x2_, y2_ - 5, OrthancStone::BitmapAnchor_BottomCenter);
     }
     else
     {
-      context.DrawText(font_, FormatLength(), x2_, y2_ + 5, BitmapAnchor_TopCenter);
+      context.DrawText(font_, FormatLength(), x2_, y2_ + 5, OrthancStone::BitmapAnchor_TopCenter);
     }
   }
     
 
   double LineMeasureTracker::GetLength() const  // In millimeters
   {
-    Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
-    Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
+    OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
+    OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
     return boost::numeric::ublas::norm_2(b - a);
   }
 
--- a/Framework/Layers/LineMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/LineMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -26,13 +26,13 @@
 #include "../Viewport/IStatusBar.h"
 #include "../Toolbox/CoordinateSystem3D.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class LineMeasureTracker : public IWorldSceneMouseTracker
   {
   private:
     IStatusBar*           statusBar_;
-    CoordinateSystem3D    slice_;
+    OrthancStone::CoordinateSystem3D    slice_;
     double                x1_;
     double                y1_;
     double                x2_;
@@ -43,7 +43,7 @@
 
   public:
     LineMeasureTracker(IStatusBar* statusBar,
-                       const CoordinateSystem3D& slice,
+                       const OrthancStone::CoordinateSystem3D& slice,
                        double x, 
                        double y,
                        uint8_t red,
@@ -56,7 +56,7 @@
       return true;
     }
 
-    virtual void Render(CairoContext& context,
+    virtual void Render(OrthancStone::CairoContext& context,
                         double zoom);
     
     double GetLength() const;  // In millimeters
--- a/Framework/Layers/RenderStyle.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/RenderStyle.cpp	Tue May 21 13:25:58 2019 +0200
@@ -23,13 +23,13 @@
 
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   RenderStyle::RenderStyle()
   {
     visible_ = true;
     reverse_ = false;
-    windowing_ = ImageWindowing_Custom;
+    windowing_ = OrthancStone::ImageWindowing_Custom;
     alpha_ = 1;
     applyLut_ = false;
     lut_ = Orthanc::EmbeddedResources::COLORMAP_HOT;
@@ -39,7 +39,7 @@
     drawColor_[2] = 255;
     customWindowCenter_ = 128;
     customWindowWidth_ = 256;
-    interpolation_ = ImageInterpolation_Nearest;
+    interpolation_ = OrthancStone::ImageInterpolation_Nearest;
     fontSize_ = 14;
   }
 
@@ -49,7 +49,7 @@
                                      float defaultCenter,
                                      float defaultWidth) const
   {
-    if (windowing_ == ImageWindowing_Custom)
+    if (windowing_ == OrthancStone::ImageWindowing_Custom)
     {
       targetCenter = customWindowCenter_;
       targetWidth = customWindowWidth_;
--- a/Framework/Layers/RenderStyle.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/RenderStyle.h	Tue May 21 13:25:58 2019 +0200
@@ -27,13 +27,13 @@
 
 #include <stdint.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   struct RenderStyle
   {
     bool visible_;
     bool reverse_;
-    ImageWindowing windowing_;
+    OrthancStone::ImageWindowing windowing_;
     float alpha_;   // In [0,1]
     bool applyLut_;
     Orthanc::EmbeddedResources::FileResourceId  lut_;
@@ -41,7 +41,7 @@
     uint8_t drawColor_[3];
     float customWindowCenter_;
     float customWindowWidth_;
-    ImageInterpolation interpolation_;
+    OrthancStone::ImageInterpolation interpolation_;
     unsigned int fontSize_;
     
     RenderStyle();
--- a/Framework/Layers/SeriesFrameRendererFactory.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/SeriesFrameRendererFactory.cpp	Tue May 21 13:25:58 2019 +0200
@@ -30,7 +30,7 @@
 #include <Plugins/Samples/Common/DicomDatasetReader.h>
 
 
-namespace OrthancStone
+namespace Deprecated
 {
   void SeriesFrameRendererFactory::ReadCurrentFrameDataset(size_t frame)
   {
--- a/Framework/Layers/SeriesFrameRendererFactory.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/SeriesFrameRendererFactory.h	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 
 #include "../Toolbox/ISeriesLoader.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class SeriesFrameRendererFactory : public ILayerRendererFactory
   {
--- a/Framework/Layers/SingleFrameRendererFactory.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/SingleFrameRendererFactory.cpp	Tue May 21 13:25:58 2019 +0200
@@ -29,7 +29,7 @@
 #include <Plugins/Samples/Common/FullOrthancDataset.h>
 #include <Plugins/Samples/Common/DicomDatasetReader.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   SingleFrameRendererFactory::SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc,
                                                          const std::string& instanceId,
--- a/Framework/Layers/SingleFrameRendererFactory.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/SingleFrameRendererFactory.h	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include "ILayerRendererFactory.h"
 #include <Plugins/Samples/Common/IOrthancConnection.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class SingleFrameRendererFactory : public ILayerRendererFactory
   {
--- a/Framework/Layers/SliceOutlineRenderer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/SliceOutlineRenderer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -21,9 +21,9 @@
 
 #include "SliceOutlineRenderer.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
-  bool SliceOutlineRenderer::RenderLayer(CairoContext& context,
+  bool SliceOutlineRenderer::RenderLayer(OrthancStone::CairoContext& context,
                                          const ViewportGeometry& view)
   {
     if (style_.visible_)
--- a/Framework/Layers/SliceOutlineRenderer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Layers/SliceOutlineRenderer.h	Tue May 21 13:25:58 2019 +0200
@@ -24,12 +24,12 @@
 #include "ILayerRenderer.h"
 #include "../Toolbox/Slice.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class SliceOutlineRenderer : public ILayerRenderer
   {
   private:
-    CoordinateSystem3D  geometry_;
+    OrthancStone::CoordinateSystem3D  geometry_;
     double              pixelSpacingX_;
     double              pixelSpacingY_;
     unsigned int        width_;
@@ -46,7 +46,7 @@
     {
     }
 
-    virtual bool RenderLayer(CairoContext& context,
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view);
 
     virtual void SetLayerStyle(const RenderStyle& style)
@@ -54,7 +54,7 @@
       style_ = style;
     }
 
-    virtual const CoordinateSystem3D& GetLayerSlice()
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerSlice()
     {
       return geometry_;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Loaders/BasicFetchingItemsSorter.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,74 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "BasicFetchingItemsSorter.h"
+
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  BasicFetchingItemsSorter::BasicFetchingItemsSorter(unsigned int itemsCount) :
+    itemsCount_(itemsCount)
+  {
+    if (itemsCount == 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  void BasicFetchingItemsSorter::Sort(std::vector<unsigned int>& target,
+                                      unsigned int current)
+  {
+    if (current >= itemsCount_)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    target.clear();
+    target.reserve(itemsCount_);
+    target.push_back(current);
+
+    const unsigned int countBelow = current;
+    const unsigned int countAbove = (itemsCount_ - 1) - current;
+    const unsigned int n = std::min(countBelow, countAbove);
+
+    for (unsigned int i = 1; i <= n; i++)
+    {
+      assert(current + i < itemsCount_ &&
+             current >= i);
+      target.push_back(current + i);
+      target.push_back(current - i);
+    }
+
+    for (unsigned int i = current - n; i > 0; i--)
+    {
+      target.push_back(i - 1);
+    }
+
+    for (unsigned int i = current + n + 1; i < itemsCount_; i++)
+    {
+      target.push_back(i);
+    }
+
+    assert(target.size() == itemsCount_);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Loaders/BasicFetchingItemsSorter.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,44 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IFetchingItemsSorter.h"
+
+namespace OrthancStone
+{
+  class BasicFetchingItemsSorter : public IFetchingItemsSorter
+  {
+  private:
+    unsigned int  itemsCount_;
+
+  public:
+    BasicFetchingItemsSorter(unsigned int itemsCount);
+
+    virtual unsigned int GetItemsCount() const
+    {
+      return itemsCount_;
+    }
+
+    virtual void Sort(std::vector<unsigned int>& target,
+                      unsigned int current);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Loaders/BasicFetchingStrategy.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,145 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "BasicFetchingStrategy.h"
+
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  void BasicFetchingStrategy::Schedule(unsigned int item,
+                                       unsigned int quality)
+  {
+    assert(item < GetItemsCount() &&
+           quality <= maxQuality_);
+      
+    if (nextQuality_[item] <= quality)
+    {
+      content_.push_back(ContentItem(item, quality));
+    }
+  }
+    
+
+  BasicFetchingStrategy::BasicFetchingStrategy(IFetchingItemsSorter* sorter,   // Takes ownership
+                                               unsigned int maxQuality) :
+    sorter_(sorter),
+    maxQuality_(maxQuality),
+    position_(0),
+    blockSize_(2)
+  {
+    if (sorter == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    nextQuality_.resize(sorter_->GetItemsCount(), 0);   // Does not change along calls to "SetCurrent()"
+      
+    SetCurrent(0);
+  }
+
+
+  void BasicFetchingStrategy::SetBlockSize(unsigned int size)
+  {
+    if (size <= 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    blockSize_ = size;
+  }
+
+  
+  bool BasicFetchingStrategy::GetNext(unsigned int& item,
+                                      unsigned int& quality)
+  {
+    if (position_ >= content_.size())
+    {
+      return false;
+    }
+    else
+    {
+      item = content_[position_].GetItem();       
+      quality = content_[position_].GetQuality();
+
+      assert(nextQuality_[item] <= quality);
+      nextQuality_[item] = quality + 1;
+
+      position_ ++;
+      return true;
+    }
+  }
+
+  
+  void BasicFetchingStrategy::SetCurrent(unsigned int item)
+  {
+    // TODO - This function is O(N) complexity where "N" is the
+    // number of items times the max quality. Could use a LRU index.
+
+    position_ = 0;
+      
+    std::vector<unsigned int> v;
+    sorter_->Sort(v, item);
+
+    assert(v.size() == GetItemsCount());
+
+    if (v.size() == 0)
+    {
+      return;
+    }
+      
+    content_.clear();
+    content_.reserve(v.size() * maxQuality_);
+
+    Schedule(v.front(), maxQuality_);
+
+    for (unsigned int q = 0; q <= maxQuality_; q++)
+    {
+      unsigned int start = 1 + q * blockSize_;
+      unsigned int end = start + blockSize_;
+
+      if (q == maxQuality_ ||
+          end > v.size())
+      {
+        end = static_cast<int>(v.size());
+      }
+
+      unsigned int a = 0;
+      if (maxQuality_ >= q + 1)
+      {
+        a = maxQuality_ - q - 1;
+      }
+        
+      for (unsigned int j = a; j <= maxQuality_; j++)
+      {
+        for (unsigned int i = start; i < end; i++)
+        {
+          Schedule(v[i], j);
+        }
+      }
+    }
+  }
+
+  
+  void BasicFetchingStrategy::RecycleFurthest(unsigned int& item)
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Loaders/BasicFetchingStrategy.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,94 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IFetchingItemsSorter.h"
+#include "IFetchingStrategy.h"
+
+#include <memory>
+
+namespace OrthancStone
+{
+  class BasicFetchingStrategy : public IFetchingStrategy
+  {
+  private:
+    class ContentItem
+    {
+    private:
+      unsigned int  item_;
+      unsigned int  quality_;
+
+    public:
+      ContentItem(unsigned int item,
+           unsigned int quality) :
+        item_(item),
+        quality_(quality)
+      {
+      }
+
+      unsigned int GetItem() const
+      {
+        return item_;
+      }
+
+      unsigned int GetQuality() const
+      {
+        return quality_;
+      }
+    };
+
+    std::auto_ptr<IFetchingItemsSorter>  sorter_;
+    std::vector<unsigned int>            nextQuality_;
+    unsigned int                         maxQuality_;
+    std::vector<ContentItem>             content_;
+    size_t                               position_;
+    unsigned int                         blockSize_;
+
+    void Schedule(unsigned int item,
+                  unsigned int quality);
+    
+  public:
+    BasicFetchingStrategy(IFetchingItemsSorter* sorter,   // Takes ownership
+                          unsigned int maxQuality);
+
+    virtual unsigned int GetItemsCount() const
+    {
+      return sorter_->GetItemsCount();
+    }
+
+    virtual unsigned int GetMaxQuality() const
+    {
+      return maxQuality_;
+    }
+
+    // WARNING - This parameters is only considered during the next
+    // call to SetCurrent().
+    void SetBlockSize(unsigned int size);
+
+    virtual bool GetNext(unsigned int& item,
+                         unsigned int& quality);
+    
+    virtual void SetCurrent(unsigned int item);
+
+    virtual void RecycleFurthest(unsigned int& item);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Loaders/IFetchingItemsSorter.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,42 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <boost/noncopyable.hpp>
+#include <vector>
+
+namespace OrthancStone
+{
+  class IFetchingItemsSorter : public boost::noncopyable
+  {
+  public:
+    virtual ~IFetchingItemsSorter()
+    {
+    }
+
+    virtual unsigned int GetItemsCount() const = 0;
+
+    // Sort a set of items given the current item
+    virtual void Sort(std::vector<unsigned int>& target,
+                      unsigned int current) = 0;
+  };
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Loaders/IFetchingStrategy.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,49 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <boost/noncopyable.hpp>
+
+namespace OrthancStone
+{
+  class IFetchingStrategy : public boost::noncopyable
+  {
+  public:
+    virtual ~IFetchingStrategy()
+    {
+    }
+
+    virtual unsigned int GetItemsCount() const = 0;
+
+    virtual unsigned int GetMaxQuality() const = 0;
+
+    virtual bool GetNext(unsigned int& item,
+                         unsigned int& quality) = 0;
+
+    virtual void SetCurrent(unsigned int item) = 0;
+
+    // Ask the strategy to re-schedule the item with the lowest
+    // priority in the fetching order. This allows to know which item
+    // should be dropped from a cache.
+    virtual void RecycleFurthest(unsigned int& item) = 0;
+  };
+};
--- a/Framework/OpenGL/OpenGLShader.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/OpenGL/OpenGLShader.cpp	Tue May 21 13:25:58 2019 +0200
@@ -35,7 +35,7 @@
       GLint sourceStringLengths[1];
 
       sourceString[0] = source.c_str();
-      sourceStringLengths[0] = source.length();
+      sourceStringLengths[0] = static_cast<GLint>(source.length());
       GLuint shader = glCreateShader(type);
 
       if (shader == 0)
--- a/Framework/Radiography/RadiographyDicomLayer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -54,7 +54,7 @@
 
   void RadiographyDicomLayer::SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset)
   {
-    converter_.reset(new DicomFrameConverter);
+    converter_.reset(new Deprecated::DicomFrameConverter);
     converter_->ReadParameters(dataset);
     ApplyConverter();
 
@@ -112,7 +112,7 @@
   }
 
 
-  void RadiographyDicomLayer::SetDicomFrameConverter(DicomFrameConverter* converter)
+  void RadiographyDicomLayer::SetDicomFrameConverter(Deprecated::DicomFrameConverter* converter)
   {
     converter_.reset(converter);
   }
--- a/Framework/Radiography/RadiographyDicomLayer.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.h	Tue May 21 13:25:58 2019 +0200
@@ -21,19 +21,20 @@
 
 #pragma once
 
+#include "../Toolbox/DicomFrameConverter.h"
 #include "RadiographyLayer.h"
+
 #include <Plugins/Samples/Common/FullOrthancDataset.h>
 
 namespace OrthancStone
 {
   class RadiographyScene;
-  class DicomFrameConverter;
 
   class RadiographyDicomLayer : public RadiographyLayer
   {
   private:
     std::auto_ptr<Orthanc::ImageAccessor>  source_;  // Content of PixelData
-    std::auto_ptr<DicomFrameConverter>     converter_;
+    std::auto_ptr<Deprecated::DicomFrameConverter>     converter_;
     std::auto_ptr<Orthanc::ImageAccessor>  converted_;  // Float32
     std::string                            instanceId_;
     unsigned int                           frame_;
@@ -65,10 +66,10 @@
 
     const Orthanc::ImageAccessor* GetSourceImage() const {return source_.get();}  // currently need this access to serialize scene in plain old data to send to a WASM worker
 
-    const DicomFrameConverter& GetDicomFrameConverter() const {return *converter_;} // currently need this access to serialize scene in plain old data to send to a WASM worker
+    const Deprecated::DicomFrameConverter& GetDicomFrameConverter() const {return *converter_;} // currently need this access to serialize scene in plain old data to send to a WASM worker
     
      // Takes ownership
-    void SetDicomFrameConverter(DicomFrameConverter* converter);
+    void SetDicomFrameConverter(Deprecated::DicomFrameConverter* converter);
 
     virtual void Render(Orthanc::ImageAccessor& buffer,
                         const AffineTransform2D& viewTransform,
--- a/Framework/Radiography/RadiographyLayerCropTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerCropTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -66,7 +66,7 @@
 
   RadiographyLayerCropTracker::RadiographyLayerCropTracker(UndoRedoStack& undoRedoStack,
                                                            RadiographyScene& scene,
-                                                           const ViewportGeometry& view,
+                                                           const Deprecated::ViewportGeometry& view,
                                                            size_t layer,
                                                            const ControlPoint& startControlPoint) :
     undoRedoStack_(undoRedoStack),
@@ -100,8 +100,8 @@
                                               int displayY,
                                               double sceneX,
                                               double sceneY,
-                                              const std::vector<Touch>& displayTouches,
-                                              const std::vector<Touch>& sceneTouches)
+                                              const std::vector<Deprecated::Touch>& displayTouches,
+                                              const std::vector<Deprecated::Touch>& sceneTouches)
   {
     if (accessor_.IsValid())
     {
--- a/Framework/Radiography/RadiographyLayerCropTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerCropTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -28,7 +28,7 @@
 
 namespace OrthancStone
 {
-  class RadiographyLayerCropTracker : public IWorldSceneMouseTracker
+  class RadiographyLayerCropTracker : public Deprecated::IWorldSceneMouseTracker
   {
   private:
     class UndoRedoCommand;
@@ -44,7 +44,7 @@
   public:
     RadiographyLayerCropTracker(UndoRedoStack& undoRedoStack,
                                 RadiographyScene& scene,
-                                const ViewportGeometry& view,
+                                const Deprecated::ViewportGeometry& view,
                                 size_t layer,
                                 const ControlPoint& startControlPoint);
 
@@ -62,7 +62,7 @@
                            int displayY,
                            double sceneX,
                            double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
+                           const std::vector<Deprecated::Touch>& displayTouches,
+                           const std::vector<Deprecated::Touch>& sceneTouches);
   };
 }
--- a/Framework/Radiography/RadiographyLayerMaskTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerMaskTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -85,7 +85,7 @@
 
   RadiographyLayerMaskTracker::RadiographyLayerMaskTracker(UndoRedoStack& undoRedoStack,
                                                            RadiographyScene& scene,
-                                                           const ViewportGeometry& view,
+                                                           const Deprecated::ViewportGeometry& view,
                                                            size_t layer,
                                                            const ControlPoint& startSceneControlPoint) :
     undoRedoStack_(undoRedoStack),
@@ -116,8 +116,8 @@
                                               int displayY,
                                               double sceneX,
                                               double sceneY,
-                                              const std::vector<Touch>& displayTouches,
-                                              const std::vector<Touch>& sceneTouches)
+                                              const std::vector<Deprecated::Touch>& displayTouches,
+                                              const std::vector<Deprecated::Touch>& sceneTouches)
   {
     if (accessor_.IsValid())
     {
--- a/Framework/Radiography/RadiographyLayerMaskTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerMaskTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -28,7 +28,7 @@
 
 namespace OrthancStone
 {
-  class RadiographyLayerMaskTracker : public IWorldSceneMouseTracker
+  class RadiographyLayerMaskTracker : public Deprecated::IWorldSceneMouseTracker
   {
   private:
     class UndoRedoCommand;
@@ -41,7 +41,7 @@
   public:
     RadiographyLayerMaskTracker(UndoRedoStack& undoRedoStack,
                                 RadiographyScene& scene,
-                                const ViewportGeometry& view,
+                                const Deprecated::ViewportGeometry& view,
                                 size_t layer,
                                 const ControlPoint& startSceneControlPoint);
 
@@ -59,7 +59,7 @@
                            int displayY,
                            double sceneX,
                            double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
+                           const std::vector<Deprecated::Touch>& displayTouches,
+                           const std::vector<Deprecated::Touch>& sceneTouches);
   };
 }
--- a/Framework/Radiography/RadiographyLayerMoveTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerMoveTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -98,8 +98,8 @@
                                               int displayY,
                                               double sceneX,
                                               double sceneY,
-                                              const std::vector<Touch>& displayTouches,
-                                              const std::vector<Touch>& sceneTouches)
+                                              const std::vector<Deprecated::Touch>& displayTouches,
+                                              const std::vector<Deprecated::Touch>& sceneTouches)
   {
     if (accessor_.IsValid())
     {
--- a/Framework/Radiography/RadiographyLayerMoveTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerMoveTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -27,7 +27,7 @@
 
 namespace OrthancStone
 {
-  class RadiographyLayerMoveTracker : public IWorldSceneMouseTracker
+  class RadiographyLayerMoveTracker : public Deprecated::IWorldSceneMouseTracker
   {
   private:
     class UndoRedoCommand;
@@ -62,7 +62,7 @@
                            int displayY,
                            double sceneX,
                            double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
+                           const std::vector<Deprecated::Touch>& displayTouches,
+                           const std::vector<Deprecated::Touch>& sceneTouches);
   };
 }
--- a/Framework/Radiography/RadiographyLayerResizeTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerResizeTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -159,8 +159,8 @@
                                                 int displayY,
                                                 double sceneX,
                                                 double sceneY,
-                                                const std::vector<Touch>& displayTouches,
-                                                const std::vector<Touch>& sceneTouches)
+                                                const std::vector<Deprecated::Touch>& displayTouches,
+                                                const std::vector<Deprecated::Touch>& sceneTouches)
   {
     static const double ROUND_SCALING = 0.1;
         
--- a/Framework/Radiography/RadiographyLayerResizeTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerResizeTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -27,7 +27,7 @@
 
 namespace OrthancStone
 {
-  class RadiographyLayerResizeTracker : public IWorldSceneMouseTracker
+  class RadiographyLayerResizeTracker : public Deprecated::IWorldSceneMouseTracker
   {
   private:
     class UndoRedoCommand;
@@ -63,7 +63,7 @@
                            int displayY,
                            double sceneX,
                            double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
+                           const std::vector<Deprecated::Touch>& displayTouches,
+                           const std::vector<Deprecated::Touch>& sceneTouches);
   };
 }
--- a/Framework/Radiography/RadiographyLayerRotateTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerRotateTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -88,7 +88,7 @@
 
   RadiographyLayerRotateTracker::RadiographyLayerRotateTracker(UndoRedoStack& undoRedoStack,
                                                                RadiographyScene& scene,
-                                                               const ViewportGeometry& view,
+                                                               const Deprecated::ViewportGeometry& view,
                                                                size_t layer,
                                                                double x,
                                                                double y,
@@ -133,8 +133,8 @@
                                                 int displayY,
                                                 double sceneX,
                                                 double sceneY,
-                                                const std::vector<Touch>& displayTouches,
-                                                const std::vector<Touch>& sceneTouches)
+                                                const std::vector<Deprecated::Touch>& displayTouches,
+                                                const std::vector<Deprecated::Touch>& sceneTouches)
   {
     static const double ROUND_ANGLE = 15.0 / 180.0 * boost::math::constants::pi<double>(); 
         
--- a/Framework/Radiography/RadiographyLayerRotateTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerRotateTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -29,7 +29,7 @@
 
 namespace OrthancStone
 {
-  class RadiographyLayerRotateTracker : public IWorldSceneMouseTracker
+  class RadiographyLayerRotateTracker : public Deprecated::IWorldSceneMouseTracker
   {
   private:
     class UndoRedoCommand;
@@ -49,7 +49,7 @@
   public:
     RadiographyLayerRotateTracker(UndoRedoStack& undoRedoStack,
                                   RadiographyScene& scene,
-                                  const ViewportGeometry& view,
+                                  const Deprecated::ViewportGeometry& view,
                                   size_t layer,
                                   double x,
                                   double y,
@@ -69,7 +69,7 @@
                            int displayY,
                            double sceneX,
                            double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
+                           const std::vector<Deprecated::Touch>& displayTouches,
+                           const std::vector<Deprecated::Touch>& sceneTouches);
   };
 }
--- a/Framework/Radiography/RadiographyScene.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.cpp	Tue May 21 13:25:58 2019 +0200
@@ -344,7 +344,7 @@
   RadiographyLayer& RadiographyScene::LoadDicomImage(Orthanc::ImageAccessor* dicomImage, // takes ownership
                                                      const std::string& instance,
                                                      unsigned int frame,
-                                                     DicomFrameConverter* converter,  // takes ownership
+                                                     Deprecated::DicomFrameConverter* converter,  // takes ownership
                                                      PhotometricDisplayMode preferredPhotometricDisplayMode,
                                                      RadiographyLayer::Geometry* geometry)
   {
@@ -364,7 +364,7 @@
     return layer;
   }
 
-  RadiographyLayer& RadiographyScene::LoadDicomFrame(OrthancApiClient& orthanc,
+  RadiographyLayer& RadiographyScene::LoadDicomFrame(Deprecated::OrthancApiClient& orthanc,
                                                      const std::string& instance,
                                                      unsigned int frame,
                                                      bool httpCompression,
@@ -379,18 +379,18 @@
     }
 
     {
-      IWebService::HttpHeaders headers;
+      Deprecated::IWebService::HttpHeaders headers;
       std::string uri = "/instances/" + instance + "/tags";
 
       orthanc.GetBinaryAsync(
             uri, headers,
-            new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage>
+            new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage>
             (*this, &RadiographyScene::OnTagsReceived), NULL,
             new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
     }
 
     {
-      IWebService::HttpHeaders headers;
+      Deprecated::IWebService::HttpHeaders headers;
       headers["Accept"] = "image/x-portable-arbitrarymap";
 
       if (httpCompression)
@@ -403,7 +403,7 @@
 
       orthanc.GetBinaryAsync(
             uri, headers,
-            new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage>
+            new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage>
             (*this, &RadiographyScene::OnFrameReceived), NULL,
             new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
     }
@@ -412,7 +412,7 @@
   }
 
 
-  RadiographyLayer& RadiographyScene::LoadDicomWebFrame(IWebService& web)
+  RadiographyLayer& RadiographyScene::LoadDicomWebFrame(Deprecated::IWebService& web)
   {
     RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this));
 
@@ -422,7 +422,7 @@
 
 
 
-  void RadiographyScene::OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
+  void RadiographyScene::OnTagsReceived(const Deprecated::OrthancApiClient::BinaryResponseReadyMessage& message)
   {
     size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>
         (message.GetPayload()).GetValue();
@@ -452,7 +452,7 @@
   }
 
 
-  void RadiographyScene::OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
+  void RadiographyScene::OnFrameReceived(const Deprecated::OrthancApiClient::BinaryResponseReadyMessage& message)
   {
     size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue();
 
@@ -726,7 +726,7 @@
   }
 
 
-  void RadiographyScene::ExportDicom(OrthancApiClient& orthanc,
+  void RadiographyScene::ExportDicom(Deprecated::OrthancApiClient& orthanc,
                                      const Json::Value& dicomTags,
                                      const std::string& parentOrthancId,
                                      double pixelSpacingX,
@@ -741,7 +741,7 @@
 
     orthanc.PostJsonAsyncExpectJson(
           "/tools/create-dicom", createDicomRequestContent,
-          new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage>
+          new Callable<RadiographyScene, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
           (*this, &RadiographyScene::OnDicomExported),
           NULL, NULL);
 
@@ -750,7 +750,7 @@
 
   // Export using PAM is faster than using PNG, but requires Orthanc
   // core >= 1.4.3
-  void RadiographyScene::ExportDicom(OrthancApiClient& orthanc,
+  void RadiographyScene::ExportDicom(Deprecated::OrthancApiClient& orthanc,
                                      const Orthanc::DicomMap& dicom,
                                      const std::string& parentOrthancId,
                                      double pixelSpacingX,
@@ -778,19 +778,19 @@
     ExportDicom(orthanc, jsonTags, parentOrthancId, pixelSpacingX, pixelSpacingY, invert, interpolation, usePam);
   }
 
-  void RadiographyScene::OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message)
+  void RadiographyScene::OnDicomExported(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
   {
     LOG(INFO) << "DICOM export was successful: "
               << message.GetJson().toStyledString();
   }
 
 
-  void RadiographyScene::OnDicomWebReceived(const IWebService::HttpRequestSuccessMessage& message)
+  void RadiographyScene::OnDicomWebReceived(const Deprecated::IWebService::HttpRequestSuccessMessage& message)
   {
     LOG(INFO) << "DICOMweb WADO-RS received: " << message.GetAnswerSize() << " bytes";
 
-    const IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders();
-    for (IWebService::HttpHeaders::const_iterator
+    const Deprecated::IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders();
+    for (Deprecated::IWebService::HttpHeaders::const_iterator
          it = h.begin(); it != h.end(); ++it)
     {
       printf("[%s] = [%s]\n", it->first.c_str(), it->second.c_str());
--- a/Framework/Radiography/RadiographyScene.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.h	Tue May 21 13:25:58 2019 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "RadiographyLayer.h"
+#include "../Toolbox/DicomFrameConverter.h"
 #include "../Toolbox/OrthancApiClient.h"
 #include "Framework/StoneEnumerations.h"
 #include "Core/Images/Image.h"
@@ -30,7 +31,6 @@
 namespace OrthancStone
 {
   class RadiographyDicomLayer;
-  class DicomFrameConverter;
 
   class RadiographyScene :
       public IObserver,
@@ -149,13 +149,13 @@
   protected:
     RadiographyLayer& RegisterLayer(RadiographyLayer* layer);
 
-    void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message);
+    void OnTagsReceived(const Deprecated::OrthancApiClient::BinaryResponseReadyMessage& message);
 
-    virtual void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message);
+    virtual void OnFrameReceived(const Deprecated::OrthancApiClient::BinaryResponseReadyMessage& message);
     
-    void OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message);
+    void OnDicomExported(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
 
-    void OnDicomWebReceived(const IWebService::HttpRequestSuccessMessage& message);
+    void OnDicomWebReceived(const Deprecated::IWebService::HttpRequestSuccessMessage& message);
 
     void OnLayerEdited(const RadiographyLayer::LayerEditedMessage& message);
   public:
@@ -193,17 +193,17 @@
     virtual RadiographyLayer& LoadDicomImage(Orthanc::ImageAccessor* dicomImage, // takes ownership
                                              const std::string& instance,
                                              unsigned int frame,
-                                             DicomFrameConverter* converter,  // takes ownership
+                                             Deprecated::DicomFrameConverter* converter,  // takes ownership
                                              PhotometricDisplayMode preferredPhotometricDisplayMode,
                                              RadiographyLayer::Geometry* geometry);
 
-    virtual RadiographyLayer& LoadDicomFrame(OrthancApiClient& orthanc,
+    virtual RadiographyLayer& LoadDicomFrame(Deprecated::OrthancApiClient& orthanc,
                                              const std::string& instance,
                                              unsigned int frame,
                                              bool httpCompression,
                                              RadiographyLayer::Geometry* geometry); // pass NULL if you want default geometry
 
-    RadiographyLayer& LoadDicomWebFrame(IWebService& web);
+    RadiographyLayer& LoadDicomWebFrame(Deprecated::IWebService& web);
 
     void RemoveLayer(size_t layerIndex);
 
@@ -278,7 +278,7 @@
 
     // Export using PAM is faster than using PNG, but requires Orthanc
     // core >= 1.4.3
-    void ExportDicom(OrthancApiClient& orthanc,
+    void ExportDicom(Deprecated::OrthancApiClient& orthanc,
                      const Orthanc::DicomMap& dicom,
                      const std::string& parentOrthancId,
                      double pixelSpacingX,
@@ -287,7 +287,7 @@
                      ImageInterpolation interpolation,
                      bool usePam);
 
-    void ExportDicom(OrthancApiClient& orthanc,
+    void ExportDicom(Deprecated::OrthancApiClient& orthanc,
                      const Json::Value& dicomTags,
                      const std::string& parentOrthancId,
                      double pixelSpacingX,
--- a/Framework/Radiography/RadiographySceneReader.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographySceneReader.cpp	Tue May 21 13:25:58 2019 +0200
@@ -32,7 +32,7 @@
 {
 
   void RadiographySceneBuilder::Read(const Json::Value& input, Orthanc::ImageAccessor* dicomImage /* takes ownership */,
-                                     DicomFrameConverter* dicomFrameConverter  /* takes ownership */,
+                                     Deprecated::DicomFrameConverter* dicomFrameConverter  /* takes ownership */,
                                      PhotometricDisplayMode preferredPhotometricDisplayMode
                                      )
   {
--- a/Framework/Radiography/RadiographySceneReader.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographySceneReader.h	Tue May 21 13:25:58 2019 +0200
@@ -26,13 +26,13 @@
 #include "RadiographyDicomLayer.h"
 #include "RadiographyMaskLayer.h"
 #include "RadiographyTextLayer.h"
+#include "../Toolbox/OrthancApiClient.h"
+
 #include <json/value.h>
 #include <Core/Images/FontRegistry.h>
 
 namespace OrthancStone
 {
-  class OrthancApiClient;
-
   // HACK: I had to introduce this builder class in order to be able to recreate a RadiographyScene
   // from a serialized scene that is passed to web-workers.
   // It needs some architecturing...
@@ -42,7 +42,7 @@
     RadiographyScene&                               scene_;
     const Orthanc::FontRegistry*                    fontRegistry_;
     std::auto_ptr<Orthanc::ImageAccessor>           dicomImage_;
-    std::auto_ptr<DicomFrameConverter>              dicomFrameConverter_;
+    std::auto_ptr<Deprecated::DicomFrameConverter>              dicomFrameConverter_;
     PhotometricDisplayMode                          preferredPhotometricDisplayMode_;
 
   public:
@@ -55,7 +55,7 @@
     void Read(const Json::Value& input);
     void Read(const Json::Value& input,
               Orthanc::ImageAccessor* dicomImage, // takes ownership
-              DicomFrameConverter* dicomFrameConverter, // takes ownership
+              Deprecated::DicomFrameConverter* dicomFrameConverter, // takes ownership
               PhotometricDisplayMode preferredPhotometricDisplayMode
               );
 
@@ -72,10 +72,10 @@
 
   class RadiographySceneReader : public RadiographySceneBuilder
   {
-    OrthancApiClient&             orthancApiClient_;
+    Deprecated::OrthancApiClient&             orthancApiClient_;
 
   public:
-    RadiographySceneReader(RadiographyScene& scene, OrthancApiClient& orthancApiClient) :
+    RadiographySceneReader(RadiographyScene& scene, Deprecated::OrthancApiClient& orthancApiClient) :
       RadiographySceneBuilder(scene),
       orthancApiClient_(orthancApiClient)
     {
--- a/Framework/Radiography/RadiographyWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -151,7 +151,7 @@
 
 
   bool RadiographyWidget::RenderScene(CairoContext& context,
-                                      const ViewportGeometry& view)
+                                      const Deprecated::ViewportGeometry& view)
   {
     cairo_t* cr = context.GetObject();
 
--- a/Framework/Radiography/RadiographyWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -30,7 +30,7 @@
   class RadiographyMaskLayer;
 
   class RadiographyWidget :
-    public WorldSceneWidget,
+    public Deprecated::WorldSceneWidget,
     public IObserver
   {
   private:
@@ -53,7 +53,7 @@
     }
 
     virtual bool RenderScene(CairoContext& context,
-                             const ViewportGeometry& view);
+                             const Deprecated::ViewportGeometry& view);
 
     virtual void RenderBackground(Orthanc::ImageAccessor& image, float minValue, float maxValue);
 
--- a/Framework/Radiography/RadiographyWindowingTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyWindowingTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -164,8 +164,8 @@
                                               int displayY,
                                               double sceneX,
                                               double sceneY,
-                                              const std::vector<Touch>& displayTouches,
-                                              const std::vector<Touch>& sceneTouches)
+                                              const std::vector<Deprecated::Touch>& displayTouches,
+                                              const std::vector<Deprecated::Touch>& sceneTouches)
   {
     // This follows the behavior of the Osimis Web viewer:
     // https://bitbucket.org/osimis/osimis-webviewer-plugin/src/master/frontend/src/app/viewport/image-plugins/windowing-viewport-tool.class.js
--- a/Framework/Radiography/RadiographyWindowingTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Radiography/RadiographyWindowingTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -27,7 +27,7 @@
 
 namespace OrthancStone
 {
-  class RadiographyWindowingTracker : public IWorldSceneMouseTracker
+  class RadiographyWindowingTracker : public Deprecated::IWorldSceneMouseTracker
   {   
   public:
     enum Action
@@ -83,7 +83,7 @@
                            int displayY,
                            double sceneX,
                            double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
+                           const std::vector<Deprecated::Touch>& displayTouches,
+                           const std::vector<Deprecated::Touch>& sceneTouches);
   };
 }
--- a/Framework/Scene2D/IPointerTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/IPointerTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -21,6 +21,8 @@
 
 #pragma once
 
+#if 0
+
 #include "PointerEvent.h"
 
 namespace OrthancStone
@@ -44,3 +46,5 @@
     virtual void Release() = 0;
   };
 }
+
+#endif
--- a/Framework/Scene2D/Internals/FixedPointAligner.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/Internals/FixedPointAligner.cpp	Tue May 21 13:25:58 2019 +0200
@@ -18,29 +18,31 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
 
-
+#include <Framework/Scene2DViewport/ViewportController.h>
 #include "FixedPointAligner.h"
 
 namespace OrthancStone
 {
   namespace Internals
   {
-    FixedPointAligner::FixedPointAligner(Scene2D& scene,
-                                         const ScenePoint2D& p) :
-      scene_(scene),
-      canvas_(p)
+    FixedPointAligner::FixedPointAligner(ViewportControllerWPtr controllerW,
+                                         const ScenePoint2D& p) 
+      : controllerW_(controllerW)
+      , canvas_(p)
     {
-      pivot_ = canvas_.Apply(scene_.GetCanvasToSceneTransform());
+      ViewportControllerPtr controller = controllerW_.lock();
+      pivot_ = canvas_.Apply(controller->GetCanvasToSceneTransform());
     }
 
     
     void FixedPointAligner::Apply()
     {
-      ScenePoint2D p = canvas_.Apply(scene_.GetCanvasToSceneTransform());
+      ViewportControllerPtr controller = controllerW_.lock();
+      ScenePoint2D p = canvas_.Apply(controller->GetCanvasToSceneTransform());
 
-      scene_.SetSceneToCanvasTransform(
+      controller->SetSceneToCanvasTransform(
         AffineTransform2D::Combine(
-          scene_.GetSceneToCanvasTransform(),
+          controller->GetSceneToCanvasTransform(),
           AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
                                           p.GetY() - pivot_.GetY())));
     }
--- a/Framework/Scene2D/Internals/FixedPointAligner.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/Internals/FixedPointAligner.h	Tue May 21 13:25:58 2019 +0200
@@ -18,11 +18,10 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
 
-
 #pragma once
 
-#include "../Scene2D.h"
-#include "../ScenePoint2D.h"
+#include <Framework/Scene2DViewport/PointerTypes.h>
+#include <Framework/Scene2D/ScenePoint2D.h>
 
 namespace OrthancStone
 {
@@ -33,12 +32,12 @@
     class FixedPointAligner : public boost::noncopyable
     {
     private:
-      Scene2D&      scene_;
-      ScenePoint2D  pivot_;
-      ScenePoint2D  canvas_;
+      ViewportControllerWPtr controllerW_;
+      ScenePoint2D           pivot_;
+      ScenePoint2D           canvas_;
 
     public:
-      FixedPointAligner(Scene2D& scene,
+      FixedPointAligner(ViewportControllerWPtr controllerW,
                         const ScenePoint2D& p);
 
       void Apply();
--- a/Framework/Scene2D/Internals/OpenGLLinesProgram.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/Internals/OpenGLLinesProgram.cpp	Tue May 21 13:25:58 2019 +0200
@@ -205,40 +205,40 @@
         }
 
         // First triangle
-        coords.push_back(x1_);
-        coords.push_back(y1_);
-        coords.push_back(1);
-        coords.push_back(x2_);
-        coords.push_back(y2_);
-        coords.push_back(-1);
-        coords.push_back(x2_);
-        coords.push_back(y2_);
-        coords.push_back(1);
+        coords.push_back(static_cast<float>(x1_));
+        coords.push_back(static_cast<float>(y1_));
+        coords.push_back(static_cast<float>(1));
+        coords.push_back(static_cast<float>(x2_));
+        coords.push_back(static_cast<float>(y2_));
+        coords.push_back(static_cast<float>(-1));
+        coords.push_back(static_cast<float>(x2_));
+        coords.push_back(static_cast<float>(y2_));
+        coords.push_back(static_cast<float>(1));
 
-        miterDirections.push_back(miterX1_);
-        miterDirections.push_back(miterY1_);
-        miterDirections.push_back(miterX2_);
-        miterDirections.push_back(miterY2_);
-        miterDirections.push_back(miterX2_);
-        miterDirections.push_back(miterY2_);
+        miterDirections.push_back(static_cast<float>(miterX1_));
+        miterDirections.push_back(static_cast<float>(miterY1_));
+        miterDirections.push_back(static_cast<float>(miterX2_));
+        miterDirections.push_back(static_cast<float>(miterY2_));
+        miterDirections.push_back(static_cast<float>(miterX2_));
+        miterDirections.push_back(static_cast<float>(miterY2_));
         
         // Second triangle
-        coords.push_back(x1_);
-        coords.push_back(y1_);
-        coords.push_back(1);
-        coords.push_back(x1_);
-        coords.push_back(y1_);
-        coords.push_back(-1);
-        coords.push_back(x2_);
-        coords.push_back(y2_);
-        coords.push_back(-1);
+        coords.push_back(static_cast<float>(x1_));
+        coords.push_back(static_cast<float>(y1_));
+        coords.push_back(static_cast<float>(1));
+        coords.push_back(static_cast<float>(x1_));
+        coords.push_back(static_cast<float>(y1_));
+        coords.push_back(static_cast<float>(-1));
+        coords.push_back(static_cast<float>(x2_));
+        coords.push_back(static_cast<float>(y2_));
+        coords.push_back(static_cast<float>(-1));
 
-        miterDirections.push_back(miterX1_);
-        miterDirections.push_back(miterY1_);
-        miterDirections.push_back(miterX1_);
-        miterDirections.push_back(miterY1_);
-        miterDirections.push_back(miterX2_);
-        miterDirections.push_back(miterY2_);
+        miterDirections.push_back(static_cast<float>(miterX1_));
+        miterDirections.push_back(static_cast<float>(miterY1_));
+        miterDirections.push_back(static_cast<float>(miterX1_));
+        miterDirections.push_back(static_cast<float>(miterY1_));
+        miterDirections.push_back(static_cast<float>(miterX2_));
+        miterDirections.push_back(static_cast<float>(miterY2_));
       }        
     };
 
@@ -247,7 +247,7 @@
                                    const PolylineSceneLayer& layer) :
       context_(context),
       verticesCount_(0),
-      thickness_(layer.GetThickness()),
+      thickness_(static_cast<float>(layer.GetThickness())),
       red_(layer.GetRedAsFloat()),
       green_(layer.GetGreenAsFloat()),
       blue_(layer.GetBlueAsFloat())
@@ -418,12 +418,15 @@
             double t1 = std::max(thickness, aliasingBorder);
             double t0 = std::max(0.0, thickness - aliasingBorder);
             
-            glUniform1f(program_->GetUniformLocation("u_thickness"), t1 / zoom);
-            glUniform1f(program_->GetUniformLocation("u_antialiasing_start"), t0 / t1);
+            glUniform1f(program_->GetUniformLocation("u_thickness"), 
+              static_cast<GLfloat>(t1 / zoom));
+            glUniform1f(program_->GetUniformLocation("u_antialiasing_start"), 
+              static_cast<GLfloat>(t0 / t1));
           }
           else
           {
-            glUniform1f(program_->GetUniformLocation("u_thickness"), thickness / zoom);
+            glUniform1f(program_->GetUniformLocation("u_thickness"), 
+              static_cast<GLfloat>(thickness / zoom));
           }
         }
         else
@@ -433,12 +436,15 @@
             double t1 = std::max(thickness, aliasingBorder / zoom);
             double t0 = std::max(0.0, thickness - aliasingBorder / zoom);
 
-            glUniform1f(program_->GetUniformLocation("u_thickness"), t1);
-            glUniform1f(program_->GetUniformLocation("u_antialiasing_start"), t0 / t1);
+            glUniform1f(program_->GetUniformLocation("u_thickness"), 
+              static_cast<GLfloat>(t1));
+            glUniform1f(program_->GetUniformLocation("u_antialiasing_start"), 
+              static_cast<GLfloat>(t0 / t1));
           }
           else
           {
-            glUniform1f(program_->GetUniformLocation("u_thickness"), thickness);
+            glUniform1f(program_->GetUniformLocation("u_thickness"), 
+              static_cast<GLfloat>(thickness));
           }
         }
 
@@ -446,12 +452,14 @@
         {
           glEnable(GL_BLEND);
           glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-          glDrawArrays(GL_TRIANGLES, 0, data.GetVerticesCount());
+          glDrawArrays(GL_TRIANGLES, 0, 
+            static_cast<GLsizei>(data.GetVerticesCount()));
           glDisable(GL_BLEND);
         }
         else
         {
-          glDrawArrays(GL_TRIANGLES, 0, data.GetVerticesCount());
+          glDrawArrays(GL_TRIANGLES, 0, 
+            static_cast<GLsizei>(data.GetVerticesCount()));
         }
 
         glDisableVertexAttribArray(locationPosition);
--- a/Framework/Scene2D/Internals/OpenGLTextProgram.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/Internals/OpenGLTextProgram.cpp	Tue May 21 13:25:58 2019 +0200
@@ -156,7 +156,8 @@
 
         double dx, dy;  // In pixels
         ComputeAnchorTranslation(dx, dy, data.GetAnchor(), 
-                                 data.GetTextWidth(), data.GetTextHeight(), data.GetBorder());
+                                 data.GetTextWidth(), data.GetTextHeight(),
+                                 static_cast<unsigned int>(data.GetBorder()));
       
         double x = data.GetX();
         double y = data.GetY();
@@ -182,7 +183,8 @@
 
         glEnable(GL_BLEND);
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-        glDrawArrays(GL_TRIANGLES, 0, data.GetCoordinatesCount() / COMPONENTS);
+        glDrawArrays(GL_TRIANGLES, 0, 
+          static_cast<GLsizei>(data.GetCoordinatesCount() / COMPONENTS));
         glDisable(GL_BLEND);
 
         glDisableVertexAttribArray(positionLocation_);
--- a/Framework/Scene2D/PanSceneTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/PanSceneTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -20,27 +20,34 @@
 
 
 #include "PanSceneTracker.h"
+#include <Framework/Scene2DViewport/ViewportController.h>
 
 namespace OrthancStone
 {
-  PanSceneTracker::PanSceneTracker(Scene2D& scene,
-                                   const PointerEvent& event) :
-    scene_(scene),
-    originalSceneToCanvas_(scene_.GetSceneToCanvasTransform()),
-    originalCanvasToScene_(scene_.GetCanvasToSceneTransform())
+  PanSceneTracker::PanSceneTracker(ViewportControllerWPtr controllerW,
+                                   const PointerEvent& event)
+    : OneGesturePointerTracker(controllerW)
+    , originalSceneToCanvas_(GetController()->GetSceneToCanvasTransform())
+    , originalCanvasToScene_(GetController()->GetCanvasToSceneTransform())
   {
     pivot_ = event.GetMainPosition().Apply(originalCanvasToScene_);
   }
 
 
-  void PanSceneTracker::Update(const PointerEvent& event)
+  void PanSceneTracker::PointerMove(const PointerEvent& event)
   {
     ScenePoint2D p = event.GetMainPosition().Apply(originalCanvasToScene_);
       
-    scene_.SetSceneToCanvasTransform(
+    GetController()->SetSceneToCanvasTransform(
       AffineTransform2D::Combine(
         originalSceneToCanvas_,
         AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
                                         p.GetY() - pivot_.GetY())));
   }
+
+  void PanSceneTracker::Cancel()
+  {
+    GetController()->SetSceneToCanvasTransform(originalSceneToCanvas_);
+  }
+
 }
--- a/Framework/Scene2D/PanSceneTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/PanSceneTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -21,27 +21,25 @@
 
 #pragma once
 
-#include "IPointerTracker.h"
-#include "Scene2D.h"
+#include "../Scene2DViewport/OneGesturePointerTracker.h"
 
 namespace OrthancStone
 {
-  class PanSceneTracker : public IPointerTracker
+  class ViewportController;
+
+  class PanSceneTracker : public OneGesturePointerTracker
   {
-  private:
-    Scene2D&           scene_;
-    ScenePoint2D       pivot_;
-    AffineTransform2D  originalSceneToCanvas_;
-    AffineTransform2D  originalCanvasToScene_;
-
   public:
-    PanSceneTracker(Scene2D& scene,
+    PanSceneTracker(ViewportControllerWPtr controllerW,
                     const PointerEvent& event);
 
-    virtual void Update(const PointerEvent& event);
+    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void Cancel() ORTHANC_OVERRIDE;
 
-    virtual void Release()
-    {
-    }
+  private:
+    ViewportControllerWPtr controllerW_;
+    ScenePoint2D           pivot_;
+    AffineTransform2D      originalSceneToCanvas_;
+    AffineTransform2D      originalCanvasToScene_;
   };
 }
--- a/Framework/Scene2D/RotateSceneTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/RotateSceneTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -18,23 +18,22 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
 
-
 #include "RotateSceneTracker.h"
+#include <Framework/Scene2DViewport/ViewportController.h>
 
 namespace OrthancStone
 {
-  RotateSceneTracker::RotateSceneTracker(Scene2D& scene,
-                                         const PointerEvent& event) :
-    scene_(scene),
-    click_(event.GetMainPosition()),
-    aligner_(scene, click_),
-    isFirst_(true),
-    originalSceneToCanvas_(scene.GetSceneToCanvasTransform())
+  RotateSceneTracker::RotateSceneTracker(ViewportControllerWPtr controllerW,
+                                         const PointerEvent& event)
+    : OneGesturePointerTracker(controllerW)
+    , click_(event.GetMainPosition())
+    , aligner_(controllerW, click_)
+    , isFirst_(true)
+    , originalSceneToCanvas_(GetController()->GetSceneToCanvasTransform())
   {
   }
-
-
-  void RotateSceneTracker::Update(const PointerEvent& event)
+  
+  void RotateSceneTracker::PointerMove(const PointerEvent& event)
   {
     ScenePoint2D p = event.GetMainPosition();
     double dx = p.GetX() - click_.GetX();
@@ -51,7 +50,7 @@
         isFirst_ = false;
       }
 
-      scene_.SetSceneToCanvasTransform(
+      GetController()->SetSceneToCanvasTransform(
         AffineTransform2D::Combine(
           AffineTransform2D::CreateRotation(a - referenceAngle_),
           originalSceneToCanvas_));
@@ -59,4 +58,10 @@
       aligner_.Apply();
     }
   }
+
+  void RotateSceneTracker::Cancel()
+  {
+    GetController()->SetSceneToCanvasTransform(originalSceneToCanvas_);
+  }
+
 }
--- a/Framework/Scene2D/RotateSceneTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/RotateSceneTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -21,29 +21,27 @@
 
 #pragma once
 
-#include "IPointerTracker.h"
+#include "../Scene2DViewport/OneGesturePointerTracker.h"
 #include "Internals/FixedPointAligner.h"
 
 namespace OrthancStone
 {
-  class RotateSceneTracker : public IPointerTracker
+  class ViewportController;
+
+  class RotateSceneTracker : public OneGesturePointerTracker
   {
-  private:
-    Scene2D&                      scene_;
-    ScenePoint2D                  click_;
-    Internals::FixedPointAligner  aligner_;
-    double                        referenceAngle_;
-    bool                          isFirst_;
-    AffineTransform2D             originalSceneToCanvas_;
-
   public:
-    RotateSceneTracker(Scene2D& scene,
+    RotateSceneTracker(ViewportControllerWPtr controllerW,
                        const PointerEvent& event);
 
-    virtual void Update(const PointerEvent& event);
+    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void Cancel() ORTHANC_OVERRIDE;
 
-    virtual void Release()
-    {
-    }
+  private:
+    ScenePoint2D                 click_;
+    Internals::FixedPointAligner aligner_;
+    double                       referenceAngle_;
+    bool                         isFirst_;
+    AffineTransform2D            originalSceneToCanvas_;
   };
 }
--- a/Framework/Scene2D/Scene2D.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/Scene2D.cpp	Tue May 21 13:25:58 2019 +0200
@@ -76,8 +76,7 @@
   
   
   Scene2D::Scene2D(const Scene2D& other) 
-    : IObservable(other.GetBroker())
-    , sceneToCanvas_(other.sceneToCanvas_)
+    : sceneToCanvas_(other.sceneToCanvas_)
     , canvasToScene_(other.canvasToScene_)
     , layerCounter_(0)
   {
@@ -221,7 +220,6 @@
 
     sceneToCanvas_ = transform;
     canvasToScene_ = inverse;
-    BroadcastMessage(SceneTransformChanged(*this));
   }
 
   void Scene2D::FitContent(unsigned int canvasWidth,
--- a/Framework/Scene2D/Scene2D.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/Scene2D.h	Tue May 21 13:25:58 2019 +0200
@@ -30,11 +30,9 @@
 
 namespace OrthancStone
 {
-  class Scene2D : public IObservable
+  class Scene2D : public boost::noncopyable
   {
   public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SceneTransformChanged, Scene2D);
-    
     class IVisitor : public boost::noncopyable
     {
     public:
@@ -60,9 +58,7 @@
     Scene2D(const Scene2D& other);
     
   public:
-    Scene2D(MessageBroker& broker) 
-      : IObservable(broker)
-      , layerCounter_(0)
+    Scene2D() : layerCounter_(0)
     {
     }
     
--- a/Framework/Scene2D/ZoomSceneTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/ZoomSceneTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -20,16 +20,17 @@
 
 
 #include "ZoomSceneTracker.h"
+#include <Framework/Scene2DViewport/ViewportController.h>
 
 namespace OrthancStone
 {
-  ZoomSceneTracker::ZoomSceneTracker(Scene2D& scene,
+  ZoomSceneTracker::ZoomSceneTracker(ViewportControllerWPtr controllerW,
                                      const PointerEvent& event,
-                                     unsigned int canvasHeight) :
-    scene_(scene),
-    clickY_(event.GetMainPosition().GetY()),
-    aligner_(scene, event.GetMainPosition()),
-    originalSceneToCanvas_(scene.GetSceneToCanvasTransform())
+                                     unsigned int canvasHeight)
+    : OneGesturePointerTracker(controllerW)
+    , clickY_(event.GetMainPosition().GetY())
+    , aligner_(controllerW, event.GetMainPosition())
+    , originalSceneToCanvas_(GetController()->GetSceneToCanvasTransform())
   {
     if (canvasHeight <= 3)
     {
@@ -42,8 +43,7 @@
     }
   }
   
-
-  void ZoomSceneTracker::Update(const PointerEvent& event)
+  void ZoomSceneTracker::PointerMove(const PointerEvent& event)
   {
     static const double MIN_ZOOM = -4;
     static const double MAX_ZOOM = 4;
@@ -51,7 +51,10 @@
     if (active_)
     {
       double y = event.GetMainPosition().GetY();
-      double dy = static_cast<double>(y - clickY_) * normalization_;  // In the range [-1,1]
+      
+      // In the range [-1,1]
+      double dy = static_cast<double>(y - clickY_) * normalization_;  
+      
       double z;
 
       // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
@@ -70,7 +73,7 @@
 
       double zoom = pow(2.0, z);
 
-      scene_.SetSceneToCanvasTransform(
+      GetController()->SetSceneToCanvasTransform(
         AffineTransform2D::Combine(
           AffineTransform2D::CreateScaling(zoom, zoom),
           originalSceneToCanvas_));
@@ -78,4 +81,9 @@
       aligner_.Apply();
     }
   }
+
+  void ZoomSceneTracker::Cancel()
+  {
+    GetController()->SetSceneToCanvasTransform(originalSceneToCanvas_);
+  }
 }
--- a/Framework/Scene2D/ZoomSceneTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Scene2D/ZoomSceneTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -21,30 +21,30 @@
 
 #pragma once
 
-#include "IPointerTracker.h"
+
+#include "../Scene2DViewport/OneGesturePointerTracker.h"
 #include "Internals/FixedPointAligner.h"
 
 namespace OrthancStone
 {
-  class ZoomSceneTracker : public IPointerTracker
+  class Scene2D;
+
+  class ZoomSceneTracker : public OneGesturePointerTracker
   {
+  public:
+    ZoomSceneTracker(ViewportControllerWPtr controllerW,
+                     const PointerEvent& event,
+                     unsigned int canvasHeight);
+
+    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void Cancel() ORTHANC_OVERRIDE;
+  
   private:
-    Scene2D&                      scene_;
     double                        clickY_;
     bool                          active_;
     double                        normalization_;
     Internals::FixedPointAligner  aligner_;
     AffineTransform2D             originalSceneToCanvas_;
 
-  public:
-    ZoomSceneTracker(Scene2D& scene,
-                     const PointerEvent& event,
-                     unsigned int canvasHeight);
-
-    virtual void Update(const PointerEvent& event);
-
-    virtual void Release()
-    {
-    }
   };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,285 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "AngleMeasureTool.h"
+#include "MeasureToolsToolbox.h"
+
+#include <Core/Logging.h>
+
+#include <boost/math/constants/constants.hpp>
+
+extern void TrackerSample_SetInfoDisplayMessage(std::string key, std::string value);
+
+namespace OrthancStone
+{
+  AngleMeasureTool::~AngleMeasureTool()
+  {
+    // this measuring tool is a RABI for the corresponding visual layers
+    // stored in the 2D scene
+    Disable();
+    RemoveFromScene();
+  }
+
+  void AngleMeasureTool::RemoveFromScene()
+  {
+    if (layersCreated)
+    {
+      assert(GetScene()->HasLayer(polylineZIndex_));
+      assert(GetScene()->HasLayer(textBaseZIndex_));
+      GetScene()->DeleteLayer(polylineZIndex_);
+      GetScene()->DeleteLayer(textBaseZIndex_);
+    }
+  }
+
+  void AngleMeasureTool::SetSide1End(ScenePoint2D pt)
+  {
+    side1End_ = pt;
+    RefreshScene();
+  }
+
+  void AngleMeasureTool::SetSide2End(ScenePoint2D pt)
+  {
+    side2End_ = pt;
+    RefreshScene();
+  }
+
+  void AngleMeasureTool::SetCenter(ScenePoint2D pt)
+  {
+    center_ = pt;
+    RefreshScene();
+  }
+  
+  PolylineSceneLayer* AngleMeasureTool::GetPolylineLayer()
+  {
+    assert(GetScene()->HasLayer(polylineZIndex_));
+    ISceneLayer* layer = &(GetScene()->GetLayer(polylineZIndex_));
+    PolylineSceneLayer* concreteLayer = dynamic_cast<PolylineSceneLayer*>(layer);
+    assert(concreteLayer != NULL);
+    return concreteLayer;
+  }
+
+  void AngleMeasureTool::RefreshScene()
+  {
+    if (IsSceneAlive())
+    {
+
+      if (IsEnabled())
+      {
+        // get the scaling factor 
+        const double pixelToScene =
+          GetScene()->GetCanvasToSceneTransform().ComputeZoom();
+
+        if (!layersCreated)
+        {
+          // Create the layers if need be
+
+          assert(textBaseZIndex_ == -1);
+          {
+            polylineZIndex_ = GetScene()->GetMaxDepth() + 100;
+            //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
+            std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
+            GetScene()->SetLayer(polylineZIndex_, layer.release());
+
+          }
+          {
+            textBaseZIndex_ = GetScene()->GetMaxDepth() + 100;
+            // create the four text background layers
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_, layer.release());
+            }
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 1, layer.release());
+            }
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 2, layer.release());
+            }
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 3, layer.release());
+            }
+
+            // and the text layer itself
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 4, layer.release());
+            }
+
+          }
+          layersCreated = true;
+        }
+        else
+        {
+          assert(GetScene()->HasLayer(polylineZIndex_));
+          assert(GetScene()->HasLayer(textBaseZIndex_));
+        }
+        {
+          // Fill the polyline layer with the measurement line
+
+          PolylineSceneLayer* polylineLayer = GetPolylineLayer();
+          polylineLayer->ClearAllChains();
+          polylineLayer->SetColor(0, 183, 17);
+
+          // sides
+          {
+            {
+              PolylineSceneLayer::Chain chain;
+              chain.push_back(side1End_);
+              chain.push_back(center_);
+              polylineLayer->AddChain(chain, false);
+            }
+            {
+              PolylineSceneLayer::Chain chain;
+              chain.push_back(side2End_);
+              chain.push_back(center_);
+              polylineLayer->AddChain(chain, false);
+            }
+          }
+
+          // handles
+          {
+            //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), side1End_, 10.0 * pixelToScene); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), side2End_, 10.0 * pixelToScene); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+          }
+
+          // arc
+          {
+            PolylineSceneLayer::Chain chain;
+
+            const double ARC_RADIUS_CANVAS_COORD = 30.0;
+            AddShortestArc(chain, *GetScene(), side1End_, center_, side2End_,
+              ARC_RADIUS_CANVAS_COORD * pixelToScene);
+            polylineLayer->AddChain(chain, false);
+          }
+        }
+        {
+          // Set the text layer
+
+          double p1cAngle = atan2(
+            side1End_.GetY() - center_.GetY(),
+            side1End_.GetX() - center_.GetX());
+
+
+          double p2cAngle = atan2(
+            side2End_.GetY() - center_.GetY(),
+            side2End_.GetX() - center_.GetX());
+
+          double delta = NormalizeAngle(p2cAngle - p1cAngle);
+
+
+          double theta = p1cAngle + delta / 2;
+
+
+          const double TEXT_CENTER_DISTANCE_CANVAS_COORD = 90;
+
+          double offsetX = TEXT_CENTER_DISTANCE_CANVAS_COORD * cos(theta);
+
+          double offsetY = TEXT_CENTER_DISTANCE_CANVAS_COORD * sin(theta);
+
+          double pointX = center_.GetX() + offsetX * pixelToScene;
+          double pointY = center_.GetY() + offsetY * pixelToScene;
+
+          char buf[64];
+          double angleDeg = RadiansToDegrees(delta);
+
+          // http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=00B0&mode=hex
+          sprintf(buf, "%0.02f\xc2\xb0", angleDeg);
+
+          SetTextLayerOutlineProperties(
+            *GetScene(), textBaseZIndex_, buf, ScenePoint2D(pointX, pointY));
+
+          // TODO:make it togglable
+          bool enableInfoDisplay = false;
+          if (enableInfoDisplay)
+          {
+            TrackerSample_SetInfoDisplayMessage("center_.GetX()",
+              boost::lexical_cast<std::string>(center_.GetX()));
+
+            TrackerSample_SetInfoDisplayMessage("center_.GetY()",
+              boost::lexical_cast<std::string>(center_.GetY()));
+
+            TrackerSample_SetInfoDisplayMessage("side1End_.GetX()",
+              boost::lexical_cast<std::string>(side1End_.GetX()));
+
+            TrackerSample_SetInfoDisplayMessage("side1End_.GetY()",
+              boost::lexical_cast<std::string>(side1End_.GetY()));
+
+            TrackerSample_SetInfoDisplayMessage("side2End_.GetX()",
+              boost::lexical_cast<std::string>(side2End_.GetX()));
+
+            TrackerSample_SetInfoDisplayMessage("side2End_.GetY()",
+              boost::lexical_cast<std::string>(side2End_.GetY()));
+
+            TrackerSample_SetInfoDisplayMessage("p1cAngle (deg)",
+              boost::lexical_cast<std::string>(RadiansToDegrees(p1cAngle)));
+
+            TrackerSample_SetInfoDisplayMessage("delta (deg)",
+              boost::lexical_cast<std::string>(RadiansToDegrees(delta)));
+
+            TrackerSample_SetInfoDisplayMessage("theta (deg)",
+              boost::lexical_cast<std::string>(RadiansToDegrees(theta)));
+
+            TrackerSample_SetInfoDisplayMessage("p2cAngle (deg)",
+              boost::lexical_cast<std::string>(RadiansToDegrees(p2cAngle)));
+
+            TrackerSample_SetInfoDisplayMessage("offsetX (pix)",
+              boost::lexical_cast<std::string>(offsetX));
+
+            TrackerSample_SetInfoDisplayMessage("offsetY (pix)",
+              boost::lexical_cast<std::string>(offsetY));
+
+            TrackerSample_SetInfoDisplayMessage("pointX",
+              boost::lexical_cast<std::string>(pointX));
+
+            TrackerSample_SetInfoDisplayMessage("pointY",
+              boost::lexical_cast<std::string>(pointY));
+
+            TrackerSample_SetInfoDisplayMessage("angleDeg",
+              boost::lexical_cast<std::string>(angleDeg));
+          }
+
+
+
+        }
+      }
+      else
+      {
+        if (layersCreated)
+        {
+          RemoveFromScene();
+          layersCreated = false;
+        }
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/AngleMeasureTool.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,76 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureTools.h"
+
+#include <Framework/Scene2D/Scene2D.h>
+#include <Framework/Scene2D/ScenePoint2D.h>
+#include <Framework/Scene2D/PolylineSceneLayer.h>
+#include <Framework/Scene2D/TextSceneLayer.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <vector>
+#include <cmath>
+
+namespace OrthancStone
+{
+  class AngleMeasureTool : public MeasureTool
+  {
+  public:
+    AngleMeasureTool(MessageBroker& broker, ViewportControllerWPtr controllerW)
+      : MeasureTool(broker, controllerW)
+      , layersCreated(false)
+      , polylineZIndex_(-1)
+      , textBaseZIndex_(-1)
+    {
+
+    }
+
+    ~AngleMeasureTool();
+
+    void SetSide1End(ScenePoint2D start);
+    void SetCenter(ScenePoint2D start);
+    void SetSide2End(ScenePoint2D start);
+
+  private:
+    PolylineSceneLayer* GetPolylineLayer();
+    
+    // 0 --> 3 are for the text background (outline)
+    // 4 is for the actual text
+    TextSceneLayer*     GetTextLayer(int index);
+    virtual void        RefreshScene() ORTHANC_OVERRIDE;
+    void                RemoveFromScene();
+
+  private:
+    ScenePoint2D side1End_;
+    ScenePoint2D side2End_;
+    ScenePoint2D center_;
+    bool         layersCreated;
+    int          polylineZIndex_;
+    int          textBaseZIndex_;
+  };
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,127 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "CreateAngleMeasureTracker.h"
+#include <Core/OrthancException.h>
+
+using namespace Orthanc;
+
+namespace OrthancStone
+{
+  CreateAngleMeasureTracker::CreateAngleMeasureTracker(
+    MessageBroker&                  broker,
+    ViewportControllerWPtr          controllerW,
+    const PointerEvent&             e)
+    : CreateMeasureTracker(controllerW)
+    , state_(CreatingSide1)
+  {
+    command_.reset(
+      new CreateAngleMeasureCommand(
+        broker,
+        controllerW,
+        e.GetMainPosition().Apply(GetScene()->GetCanvasToSceneTransform())));
+  }
+
+  CreateAngleMeasureTracker::~CreateAngleMeasureTracker()
+  {
+  }
+
+  void CreateAngleMeasureTracker::PointerMove(const PointerEvent& event)
+  {
+    assert(GetScene());
+
+    if (!alive_)
+    {
+      throw OrthancException(ErrorCode_InternalError,
+        "Internal error: wrong state in CreateAngleMeasureTracker::"
+        "PointerMove: active_ == false");
+    }
+
+    ScenePoint2D scenePos = event.GetMainPosition().Apply(
+      GetScene()->GetCanvasToSceneTransform());
+
+    switch (state_)
+    {
+    case CreatingSide1:
+      GetCommand()->SetCenter(scenePos);
+      break;
+    case CreatingSide2:
+      GetCommand()->SetSide2End(scenePos);
+      break;
+    default:
+      throw OrthancException(ErrorCode_InternalError,
+        "Wrong state in CreateAngleMeasureTracker::"
+        "PointerMove: state_ invalid");
+    }
+    //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
+    //  "scenePos.GetY() = " << scenePos.GetY();
+  }
+
+  void CreateAngleMeasureTracker::PointerUp(const PointerEvent& e)
+  {
+    // TODO: the current app does not prevent multiple PointerDown AND
+    // PointerUp to be sent to the tracker.
+    // Unless we augment the PointerEvent structure with the button index, 
+    // we cannot really tell if this pointer up event matches the initial
+    // pointer down event. Let's make it simple for now.
+
+    switch (state_)
+    {
+    case CreatingSide1:
+      state_ = CreatingSide2;
+      break;
+    case CreatingSide2:
+      throw OrthancException(ErrorCode_InternalError,
+        "Wrong state in CreateAngleMeasureTracker::"
+        "PointerUp: state_ == CreatingSide2 ; this should not happen");
+      break;
+    default:
+      throw OrthancException(ErrorCode_InternalError,
+        "Wrong state in CreateAngleMeasureTracker::"
+        "PointerMove: state_ invalid");
+    }
+  }
+
+  void CreateAngleMeasureTracker::PointerDown(const PointerEvent& e)
+  {
+    switch (state_)
+    {
+    case CreatingSide1:
+      throw OrthancException(ErrorCode_InternalError,
+        "Wrong state in CreateAngleMeasureTracker::"
+        "PointerDown: state_ == CreatingSide1 ; this should not happen");
+      break;
+    case CreatingSide2:
+      // we are done
+      alive_ = false;
+      break;
+    default:
+      throw OrthancException(ErrorCode_InternalError,
+        "Wrong state in CreateAngleMeasureTracker::"
+        "PointerMove: state_ invalid");
+    }
+  }
+
+  CreateAngleMeasureCommandPtr CreateAngleMeasureTracker::GetCommand()
+  {
+    return boost::dynamic_pointer_cast<CreateAngleMeasureCommand>(command_);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,63 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureTrackers.h"
+#include "MeasureCommands.h"
+
+#include <vector>
+
+namespace OrthancStone
+{
+  class CreateAngleMeasureTracker : public CreateMeasureTracker
+  {
+  public:
+    /**
+    When you create this tracker, you need to supply it with the undo stack
+    where it will store the commands that perform the actual measure tool
+    creation and modification.
+    In turn, a container for these commands to store the actual measuring
+    must be supplied, too
+    */
+    CreateAngleMeasureTracker(
+      MessageBroker&                  broker,
+      ViewportControllerWPtr          controllerW,
+      const PointerEvent&             e);
+
+    ~CreateAngleMeasureTracker();
+
+    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
+
+  private:
+    CreateAngleMeasureCommandPtr GetCommand();
+
+    enum State
+    {
+      CreatingSide1,
+      CreatingSide2,
+      Finished // just for debug
+    };
+    State state_;
+
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateCircleMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,23 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateCircleMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,25 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,90 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "CreateLineMeasureTracker.h"
+#include <Core/OrthancException.h>
+
+using namespace Orthanc;
+
+namespace OrthancStone
+{
+  CreateLineMeasureTracker::CreateLineMeasureTracker(
+    MessageBroker&                  broker,
+    ViewportControllerWPtr          controllerW,
+    const PointerEvent&             e)
+    : CreateMeasureTracker(controllerW)
+  {
+    command_.reset(
+      new CreateLineMeasureCommand(
+        broker,
+        controllerW,
+        e.GetMainPosition().Apply(GetScene()->GetCanvasToSceneTransform())));
+  }
+
+  CreateLineMeasureTracker::~CreateLineMeasureTracker()
+  {
+
+  }
+
+  void CreateLineMeasureTracker::PointerMove(const PointerEvent& event)
+  {
+    assert(GetScene());
+    
+    if (!alive_)
+    {
+      throw OrthancException(ErrorCode_InternalError,
+        "Internal error: wrong state in CreateLineMeasureTracker::"
+        "PointerMove: active_ == false");
+    }
+
+    ScenePoint2D scenePos = event.GetMainPosition().Apply(
+      GetScene()->GetCanvasToSceneTransform());
+
+    //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
+    //  "scenePos.GetY() = " << scenePos.GetY();
+
+    CreateLineMeasureTracker* concreteThis =
+      dynamic_cast<CreateLineMeasureTracker*>(this);
+    assert(concreteThis != NULL);
+    GetCommand()->SetEnd(scenePos);
+  }
+
+  void CreateLineMeasureTracker::PointerUp(const PointerEvent& e)
+  {
+    // TODO: the current app does not prevent multiple PointerDown AND
+    // PointerUp to be sent to the tracker.
+    // Unless we augment the PointerEvent structure with the button index, 
+    // we cannot really tell if this pointer up event matches the initial
+    // pointer down event. Let's make it simple for now.
+    alive_ = false;
+  }
+
+  void CreateLineMeasureTracker::PointerDown(const PointerEvent& e)
+  {
+    LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) "
+      "are ignored when the line measure creation tracker is active";
+  }
+
+  CreateLineMeasureCommandPtr CreateLineMeasureTracker::GetCommand()
+  {
+    return boost::dynamic_pointer_cast<CreateLineMeasureCommand>(command_);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,51 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureTrackers.h"
+
+namespace OrthancStone
+{
+  class CreateLineMeasureTracker : public CreateMeasureTracker
+  {
+  public:
+    /**
+    When you create this tracker, you need to supply it with the undo stack
+    where it will store the commands that perform the actual measure tool
+    creation and modification.
+    In turn, a container for these commands to store the actual measuring
+    must be supplied, too
+    */
+    CreateLineMeasureTracker(
+      MessageBroker&                  broker,
+      ViewportControllerWPtr          controllerW,
+      const PointerEvent&             e);
+
+    ~CreateLineMeasureTracker();
+
+    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
+
+  private:
+    CreateLineMeasureCommandPtr GetCommand();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,20 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,22 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/CreateSimpleTrackerAdapter.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,79 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IFlexiblePointerTracker.h"
+#include <Framework/Scene2D/IPointerTracker.h>
+
+
+namespace OrthancStone
+{
+#if 0
+  namespace
+  {
+    class SimpleTrackerAdapter : public IFlexiblePointerTracker
+    {
+    public:
+      SimpleTrackerAdapter(PointerTrackerPtr wrappedTracker)
+        : wrappedTracker_(wrappedTracker)
+        , active_(true)
+      {
+      }
+
+      virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE
+      {
+        if(active_)
+          wrappedTracker_->Update(event);
+      };
+      virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE
+      {
+        if (wrappedTracker_)
+        {
+          wrappedTracker_->Release();
+          wrappedTracker_ = NULL;
+        }
+        active_ = false;
+      }
+      virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE
+      {
+        // nothing to do atm
+      }
+      virtual bool IsActive() const ORTHANC_OVERRIDE
+      {
+        return active_;
+      }
+
+      virtual void Cancel() ORTHANC_OVERRIDE
+      {
+        wrappedTracker_ = NULL;
+        active_ = false;
+      }
+
+    private:
+      PointerTrackerPtr wrappedTracker_;
+      bool active_;
+    };
+  }
+
+  FlexiblePointerTrackerPtr CreateSimpleTrackerAdapter(PointerTrackerPtr t)
+  {
+    return FlexiblePointerTrackerPtr(new SimpleTrackerAdapter(t));
+  }
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,23 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,25 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/EditCircleMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,23 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/EditCircleMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,25 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/EditLineMeasureTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,23 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/EditLineMeasureTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,25 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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
+
+namespace OrthancStone
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/IFlexiblePointerTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,87 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "PointerTypes.h"
+
+#include <Framework/Scene2D/PointerEvent.h>
+
+namespace OrthancStone
+{
+  /**
+  This interface represents a flexible mouse tracker that can respond to 
+  several events and is not automatically deleted upon mouse up or when touch
+  interaction is suspended : for instance, a stateful tracker with a two-step 
+  interaction like: click & drag --> mouse up --> drag --> mouse click 
+  (for instance, for an angle measuring tracker or an ellipse tracker)
+  */
+  class IFlexiblePointerTracker : public boost::noncopyable
+  {
+  public:
+    virtual ~IFlexiblePointerTracker() {}
+
+    /**
+    This method will be repeatedly called during user interaction
+    */
+    virtual void PointerMove(const PointerEvent& event) = 0;
+
+    /**
+    This method will be called when a touch/pointer is removed (mouse up, 
+    pen lift, finger removed...)
+    */
+    virtual void PointerUp(const PointerEvent& event) = 0;
+
+    /**
+    This method will be called when a touch/pointer is added (mouse down, 
+    pen or finger press)
+
+    Important note: the initial pointer down that leads to creating the 
+    tracker is NOT sent to the tracker.
+
+    Thus, if you count the PointerDown vs PointerUp, there will be an extra
+    PointerUp.
+    */
+    virtual void PointerDown(const PointerEvent& event) = 0;
+
+    /**
+    This method will be repeatedly called by the tracker owner (for instance,
+    the application) to check whether the tracker must keep on receiving 
+    interaction or if its job is done and it should be deleted.
+    */
+    virtual bool IsAlive() const = 0;
+
+    /**
+    This will be called if the tracker needs to be dismissed without committing
+    its changes to the underlying model. If the model has been modified during
+    tracker lifetime, it must be restored to its initial value
+    */
+    virtual void Cancel() = 0;
+  };
+
+
+  /**
+  This factory adopts the supplied simple tracker and creates a flexible 
+  tracker wrapper around it.
+  */
+  FlexiblePointerTrackerPtr CreateSimpleTrackerAdapter(PointerTrackerPtr);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/LineMeasureTool.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,201 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "LineMeasureTool.h"
+#include "MeasureToolsToolbox.h"
+
+#include <Core/Logging.h>
+
+
+namespace OrthancStone
+{
+  LineMeasureTool::~LineMeasureTool()
+  {
+    // this measuring tool is a RABI for the corresponding visual layers
+    // stored in the 2D scene
+    Disable();
+    RemoveFromScene();
+  }
+
+  void LineMeasureTool::RemoveFromScene()
+  {
+    if (layersCreated)
+    {
+      assert(GetScene()->HasLayer(polylineZIndex_));
+      assert(GetScene()->HasLayer(textZIndex_));
+      GetScene()->DeleteLayer(polylineZIndex_);
+      GetScene()->DeleteLayer(textZIndex_);
+    }
+  }
+
+
+  void LineMeasureTool::SetStart(ScenePoint2D start)
+  {
+    start_ = start;
+    RefreshScene();
+  }
+
+  void LineMeasureTool::SetEnd(ScenePoint2D end)
+  {
+    end_ = end;
+    RefreshScene();
+  }
+
+  void LineMeasureTool::Set(ScenePoint2D start, ScenePoint2D end)
+  {
+    start_ = start;
+    end_ = end;
+    RefreshScene();
+  }
+
+  PolylineSceneLayer* LineMeasureTool::GetPolylineLayer()
+  {
+    assert(GetScene()->HasLayer(polylineZIndex_));
+    ISceneLayer* layer = &(GetScene()->GetLayer(polylineZIndex_));
+    PolylineSceneLayer* concreteLayer = dynamic_cast<PolylineSceneLayer*>(layer);
+    assert(concreteLayer != NULL);
+    return concreteLayer;
+  }
+
+  TextSceneLayer* LineMeasureTool::GetTextLayer()
+  {
+    assert(GetScene()->HasLayer(textZIndex_));
+    ISceneLayer* layer = &(GetScene()->GetLayer(textZIndex_));
+    TextSceneLayer* concreteLayer = dynamic_cast<TextSceneLayer*>(layer);
+    assert(concreteLayer != NULL);
+    return concreteLayer;
+  }
+
+  void LineMeasureTool::RefreshScene()
+  {
+    if (IsSceneAlive())
+    {
+      if (IsEnabled())
+      {
+        if (!layersCreated)
+        {
+          // Create the layers if need be
+
+          assert(textZIndex_ == -1);
+          {
+            polylineZIndex_ = GetScene()->GetMaxDepth() + 100;
+            //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
+            std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
+            GetScene()->SetLayer(polylineZIndex_, layer.release());
+          }
+          {
+            textZIndex_ = GetScene()->GetMaxDepth() + 100;
+            //LOG(INFO) << "set textZIndex_ to: " << textZIndex_;
+            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+            GetScene()->SetLayer(textZIndex_, layer.release());
+          }
+          layersCreated = true;
+        }
+        else
+        {
+          assert(GetScene()->HasLayer(polylineZIndex_));
+          assert(GetScene()->HasLayer(textZIndex_));
+        }
+        {
+          // Fill the polyline layer with the measurement line
+
+          PolylineSceneLayer* polylineLayer = GetPolylineLayer();
+          polylineLayer->ClearAllChains();
+          polylineLayer->SetColor(0, 223, 21);
+
+          {
+            PolylineSceneLayer::Chain chain;
+            chain.push_back(start_);
+            chain.push_back(end_);
+            polylineLayer->AddChain(chain, false);
+          }
+
+          // handles
+          {
+            //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), start_, 10.0); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), end_, 10.0); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+
+            //ScenePoint2D startC = start_.Apply(GetScene()->GetSceneToCanvasTransform());
+            //double squareSize = 10.0; 
+            //double startHandleLX = startC.GetX() - squareSize/2;
+            //double startHandleTY = startC.GetY() - squareSize / 2;
+            //double startHandleRX = startC.GetX() + squareSize / 2;
+            //double startHandleBY = startC.GetY() + squareSize / 2;
+            //ScenePoint2D startLTC(startHandleLX, startHandleTY);
+            //ScenePoint2D startRTC(startHandleRX, startHandleTY);
+            //ScenePoint2D startRBC(startHandleRX, startHandleBY);
+            //ScenePoint2D startLBC(startHandleLX, startHandleBY);
+
+            //ScenePoint2D startLT = startLTC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startRT = startRTC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startRB = startRBC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startLB = startLBC.Apply(GetScene()->GetCanvasToSceneTransform());
+
+            //PolylineSceneLayer::Chain chain;
+            //chain.push_back(startLT);
+            //chain.push_back(startRT);
+            //chain.push_back(startRB);
+            //chain.push_back(startLB);
+            //polylineLayer->AddChain(chain, true);
+          }
+
+        }
+        {
+          // Set the text layer proporeties
+
+          TextSceneLayer* textLayer = GetTextLayer();
+          double deltaX = end_.GetX() - start_.GetX();
+          double deltaY = end_.GetY() - start_.GetY();
+          double squareDist = deltaX * deltaX + deltaY * deltaY;
+          double dist = sqrt(squareDist);
+          char buf[64];
+          sprintf(buf, "%0.02f units", dist);
+          textLayer->SetText(buf);
+          textLayer->SetColor(0, 223, 21);
+
+          // TODO: for now we simply position the text overlay at the middle
+          // of the measuring segment
+          double midX = 0.5 * (end_.GetX() + start_.GetX());
+          double midY = 0.5 * (end_.GetY() + start_.GetY());
+          textLayer->SetPosition(midX, midY);
+        }
+      }
+      else
+      {
+        if (layersCreated)
+        {
+          RemoveFromScene();
+          layersCreated = false;
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/LineMeasureTool.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,71 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureTools.h"
+
+#include <Framework/Scene2D/Scene2D.h>
+#include <Framework/Scene2D/ScenePoint2D.h>
+#include <Framework/Scene2D/PolylineSceneLayer.h>
+#include <Framework/Scene2D/TextSceneLayer.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <vector>
+#include <cmath>
+
+namespace OrthancStone
+{
+  class LineMeasureTool : public MeasureTool
+  {
+  public:
+    LineMeasureTool(MessageBroker& broker, ViewportControllerWPtr controllerW)
+      : MeasureTool(broker, controllerW)
+      , layersCreated(false)
+      , polylineZIndex_(-1)
+      , textZIndex_(-1)
+    {
+
+    }
+
+    ~LineMeasureTool();
+
+    void SetStart(ScenePoint2D start);
+    void SetEnd(ScenePoint2D end);
+    void Set(ScenePoint2D start, ScenePoint2D end);
+
+  private:
+    PolylineSceneLayer* GetPolylineLayer();
+    TextSceneLayer*     GetTextLayer();
+    virtual void        RefreshScene() ORTHANC_OVERRIDE;
+    void                RemoveFromScene();
+
+  private:
+    ScenePoint2D start_;
+    ScenePoint2D end_;
+    bool         layersCreated;
+    int          polylineZIndex_;
+    int          textZIndex_;
+  };
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureCommands.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,100 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureCommands.h"
+
+#include <boost/make_shared.hpp>
+#include <boost/ref.hpp>
+
+namespace OrthancStone
+{
+  void CreateMeasureCommand::Undo()
+  {
+    // simply disable the measure tool upon undo
+    GetController()->RemoveMeasureTool(GetMeasureTool());
+  }
+
+  void CreateMeasureCommand::Redo()
+  {
+    GetController()->AddMeasureTool(GetMeasureTool());
+  }
+
+  CreateMeasureCommand::CreateMeasureCommand(ViewportControllerWPtr controllerW)
+    : TrackerCommand(controllerW)
+  {
+
+  }
+
+  CreateMeasureCommand::~CreateMeasureCommand()
+  {
+    // deleting the command should not change the model state
+    // we thus leave it as is
+  }
+
+  CreateLineMeasureCommand::CreateLineMeasureCommand(
+    MessageBroker&         broker, 
+    ViewportControllerWPtr controllerW,
+    ScenePoint2D           point)
+    : CreateMeasureCommand(controllerW)
+    , measureTool_(
+        boost::make_shared<LineMeasureTool>(boost::ref(broker), controllerW))
+  {
+    GetController()->AddMeasureTool(measureTool_);
+    measureTool_->Set(point, point);
+  }
+
+  void CreateLineMeasureCommand::SetEnd(ScenePoint2D scenePos)
+  {
+    measureTool_->SetEnd(scenePos);
+  }
+
+  CreateAngleMeasureCommand::CreateAngleMeasureCommand(
+    MessageBroker&         broker, 
+    ViewportControllerWPtr controllerW,
+    ScenePoint2D           point)
+    : CreateMeasureCommand(controllerW)
+    , measureTool_(
+      boost::make_shared<AngleMeasureTool>(boost::ref(broker), controllerW))
+  {
+    GetController()->AddMeasureTool(measureTool_);
+    measureTool_->SetSide1End(point);
+    measureTool_->SetCenter(point);
+    measureTool_->SetSide2End(point);
+  }
+
+  /** This method sets center*/
+  void CreateAngleMeasureCommand::SetCenter(ScenePoint2D scenePos)
+  {
+    measureTool_->SetCenter(scenePos);
+  }
+
+  /** This method sets end of side 2*/
+  void CreateAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos)
+  {
+    measureTool_->SetSide2End(scenePos);
+  }
+
+  ViewportControllerPtr TrackerCommand::GetController()
+  {
+    ViewportControllerPtr controller = controllerW_.lock();
+    assert(controller); // accessing dead object?
+    return controller;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureCommands.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,106 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <Framework/Scene2D/Scene2D.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+// to be moved into Stone
+#include "PointerTypes.h"
+#include "MeasureTools.h"
+#include "LineMeasureTool.h"
+#include "AngleMeasureTool.h"
+
+namespace OrthancStone
+{
+  class TrackerCommand : public boost::noncopyable
+  {
+  public:
+    TrackerCommand(ViewportControllerWPtr controllerW) 
+      : controllerW_(controllerW)
+    {
+
+    }
+    virtual void Undo() = 0;
+    virtual void Redo() = 0;
+
+  protected:
+    ViewportControllerPtr  GetController();
+    ViewportControllerWPtr controllerW_;
+  };
+
+  class CreateMeasureCommand : public TrackerCommand
+  {
+  public:
+    CreateMeasureCommand(ViewportControllerWPtr controllerW);
+    ~CreateMeasureCommand();
+    virtual void Undo() ORTHANC_OVERRIDE;
+    virtual void Redo() ORTHANC_OVERRIDE;
+  private:
+    /** Must be implemented by the subclasses that create the actual tool */
+    virtual MeasureToolPtr GetMeasureTool() = 0;
+  };
+  
+  class CreateLineMeasureCommand : public CreateMeasureCommand
+  {
+  public:
+    CreateLineMeasureCommand(
+      MessageBroker&         broker, 
+      ViewportControllerWPtr controllerW,
+      ScenePoint2D           point);
+    
+    // the starting position is set in the ctor
+    void SetEnd(ScenePoint2D scenePos);
+
+  private:
+    virtual MeasureToolPtr GetMeasureTool() ORTHANC_OVERRIDE
+    {
+      return measureTool_;
+    }
+    LineMeasureToolPtr measureTool_;
+  };
+
+
+  class CreateAngleMeasureCommand : public CreateMeasureCommand
+  {
+  public:
+    /** Ctor sets end of side 1*/
+    CreateAngleMeasureCommand(
+      MessageBroker&         broker, 
+      ViewportControllerWPtr controllerW,
+      ScenePoint2D           point);
+
+    /** This method sets center*/
+    void SetCenter(ScenePoint2D scenePos);
+
+    /** This method sets end of side 2*/
+    void SetSide2End(ScenePoint2D scenePos);
+
+  private:
+    virtual MeasureToolPtr GetMeasureTool() ORTHANC_OVERRIDE
+    {
+      return measureTool_;
+    }
+    AngleMeasureToolPtr measureTool_;
+  };
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureTools.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,97 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureTools.h"
+
+#include <Core/Logging.h>
+#include <Core/Enumerations.h>
+#include <Core/OrthancException.h>
+
+#include <boost/math/constants/constants.hpp>
+
+using namespace Orthanc;
+
+namespace OrthancStone
+{
+
+  MeasureTool::~MeasureTool()
+  {
+
+  }
+
+  void MeasureTool::Enable()
+  {
+    enabled_ = true;
+    RefreshScene();
+  }
+
+  void MeasureTool::Disable()
+  {
+    enabled_ = false;
+    RefreshScene();
+  }
+
+  bool MeasureTool::IsEnabled() const
+  {
+    return enabled_;
+  }
+
+
+  ViewportControllerPtr MeasureTool::GetController()
+  {
+    ViewportControllerPtr controller = controllerW_.lock();
+    if (!controller)
+      throw OrthancException(ErrorCode_InternalError, 
+        "Using dead ViewportController object!");
+    return controller;
+  }
+
+  OrthancStone::Scene2DPtr MeasureTool::GetScene()
+  {
+    return GetController()->GetScene();
+  }
+
+  MeasureTool::MeasureTool(MessageBroker& broker,
+    ViewportControllerWPtr controllerW)
+    : IObserver(broker)
+    , controllerW_(controllerW)
+    , enabled_(true)
+  {
+    GetController()->RegisterObserverCallback(
+      new Callable<MeasureTool, ViewportController::SceneTransformChanged>
+      (*this, &MeasureTool::OnSceneTransformChanged));
+  }
+
+
+  bool MeasureTool::IsSceneAlive() const
+  {
+    ViewportControllerPtr controller = controllerW_.lock();
+    return (controller.get() != NULL);
+  }
+
+  void MeasureTool::OnSceneTransformChanged(
+    const ViewportController::SceneTransformChanged& message)
+  {
+    RefreshScene();
+  }
+
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureTools.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,98 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <Framework/Scene2DViewport/PointerTypes.h>
+#include <Framework/Scene2DViewport/ViewportController.h>
+
+#include <Framework/Scene2D/Scene2D.h>
+#include <Framework/Scene2D/ScenePoint2D.h>
+#include <Framework/Scene2D/PolylineSceneLayer.h>
+#include <Framework/Scene2D/TextSceneLayer.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <vector>
+#include <cmath>
+
+namespace OrthancStone
+{
+  class MeasureTool : public IObserver
+  {
+  public:
+    virtual ~MeasureTool();
+
+    /**
+    Enabled tools are rendered in the scene.
+    */
+    void Enable();
+
+    /**
+    Disabled tools are not rendered in the scene. This is useful to be able
+    to use them as their own memento in command stacks (when a measure tool
+    creation command has been undone, the measure remains alive in the
+    command object but is disabled so that it can be redone later on easily)
+    */
+    void Disable();
+
+    /**
+    This method is called when the scene transform changes. It allows to 
+    recompute the visual elements whose content depend upon the scene transform
+    */
+    void OnSceneTransformChanged(
+      const ViewportController::SceneTransformChanged& message);
+
+  protected:
+    MeasureTool(MessageBroker& broker, ViewportControllerWPtr controllerW);
+
+    /**
+    The measuring tool may exist in a standalone fashion, without any available
+    scene (because the controller is dead or dying). This call allows to check 
+    before accessing the scene.
+    */
+    bool IsSceneAlive() const;
+    
+    /**
+    This is the meat of the tool: this method must [create (if needed) and]
+    update the layers and their data according to the measure tool kind and
+    current state. This is repeatedly called during user interaction
+    */
+    virtual void RefreshScene() = 0;
+
+    ViewportControllerPtr GetController();
+    Scene2DPtr GetScene();
+    
+    /**
+    enabled_ is not accessible by subclasses because there is a state machine
+    that we do not wanna mess with
+    */
+    bool IsEnabled() const;
+
+  private:
+    ViewportControllerWPtr controllerW_;
+    bool     enabled_;
+  };
+}
+
+
+extern void TrackerSample_SetInfoDisplayMessage(
+  std::string key, std::string value);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureToolsToolbox.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,336 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureToolsToolbox.h"
+
+#include <Framework/Scene2D/TextSceneLayer.h>
+
+#include <boost/math/constants/constants.hpp>
+
+namespace
+{
+  double g_pi = boost::math::constants::pi<double>();
+}
+
+namespace OrthancStone
+{
+  double RadiansToDegrees(double angleRad)
+  {
+    static const double factor = 180.0 / g_pi;
+    return angleRad * factor;
+  }
+
+  void AddSquare(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       sideLength)
+  {
+    chain.clear();
+    chain.reserve(4);
+    ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
+    //TODO: take DPI into account 
+    double handleLX = centerC.GetX() - sideLength / 2;
+    double handleTY = centerC.GetY() - sideLength / 2;
+    double handleRX = centerC.GetX() + sideLength / 2;
+    double handleBY = centerC.GetY() + sideLength / 2;
+    ScenePoint2D LTC(handleLX, handleTY);
+    ScenePoint2D RTC(handleRX, handleTY);
+    ScenePoint2D RBC(handleRX, handleBY);
+    ScenePoint2D LBC(handleLX, handleBY);
+
+    ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
+
+    chain.push_back(startLT);
+    chain.push_back(startRT);
+    chain.push_back(startRB);
+    chain.push_back(startLB);
+  }
+#if 0
+  void AddArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&      scene
+    , const ScenePoint2D& p1
+    , const ScenePoint2D& c
+    , const ScenePoint2D& p2
+    , const double&       radiusS
+    , const bool          clockwise
+    , const int           subdivisionsCount)
+  {
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    AddArc(
+      chain, scene, c, radiusS, p1cAngle, p2cAngle, 
+      clockwise, subdivisionsCount);
+  }
+#endif
+
+  void AddShortestArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&             scene
+    , const ScenePoint2D&        p1
+    , const ScenePoint2D&        c
+    , const ScenePoint2D&        p2
+    , const double&              radiusS
+    , const int                  subdivisionsCount)
+  {
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    AddShortestArc(
+      chain, scene, c, radiusS, p1cAngle, p2cAngle, subdivisionsCount);
+  }
+
+  void GetPositionOnBisectingLine(
+    ScenePoint2D&       result
+    , const ScenePoint2D& p1
+    , const ScenePoint2D& c
+    , const ScenePoint2D& p2
+    , const double d)
+  {
+    // TODO: fix correct half-plane
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    double angle = 0.5*(p1cAngle + p2cAngle);
+    double unitVectorX = cos(angle);
+    double unitVectorY = sin(angle);
+    double posX = c.GetX() + d * unitVectorX;
+    double posY = c.GetX() + d * unitVectorY;
+    result = ScenePoint2D(posX, posY);
+  }
+   
+  void AddShortestArc(
+      PolylineSceneLayer::Chain&  chain
+    , const Scene2D&              scene
+    , const ScenePoint2D&         centerS
+    , const double&               radiusS
+    , const double                startAngleRad
+    , const double                endAngleRad
+    , const int                   subdivisionsCount)
+  {
+    // this gives a signed difference between angle which
+    // is the smallest difference (in magnitude) between 
+    // the angles
+    double delta = NormalizeAngle(endAngleRad-startAngleRad);
+
+    chain.clear();
+    chain.reserve(subdivisionsCount + 1);
+
+    double angleIncr = delta/static_cast<double>(subdivisionsCount);
+
+    double theta = startAngleRad;
+    for (int i = 0; i < subdivisionsCount + 1; ++i)
+    {
+      double offsetX = radiusS * cos(theta);
+      double offsetY = radiusS * sin(theta);
+      double pointX = centerS.GetX() + offsetX;
+      double pointY = centerS.GetY() + offsetY;
+      chain.push_back(ScenePoint2D(pointX, pointY));
+      theta += angleIncr;
+    }
+  }
+
+#if 0
+  void AddArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&      scene
+    , const ScenePoint2D& centerS
+    , const double&       radiusS
+    , const double        startAngleRad
+    , const double        endAngleRad
+    , const bool          clockwise
+    , const int           subdivisionsCount)
+  {
+    double startAngleRadN = NormalizeAngle(startAngleRad);
+    double endAngleRadN = NormalizeAngle(endAngleRad);
+
+    double angle1Rad = std::min(startAngleRadN, endAngleRadN);
+    double angle2Rad = std::max(startAngleRadN, endAngleRadN);
+
+    // now we are sure angle1Rad < angle2Rad
+    // this means that if we draw from 1 to 2, it will be clockwise (
+    // increasing angles).
+    // let's fix this:
+    if (!clockwise)
+    {
+      angle2Rad -= 2 * g_pi;
+      // now we are sure angle2Rad < angle1Rad (since they were normalized) 
+      // and, thus, going from 1 to 2 means the angle values will DECREASE,
+      // which is the definition of anticlockwise
+    }
+
+    chain.clear();
+    chain.reserve(subdivisionsCount + 1);
+
+    double angleIncr = (angle2Rad - angle1Rad)
+      / static_cast<double>(subdivisionsCount);
+
+    double theta = angle1Rad;
+    for (int i = 0; i < subdivisionsCount + 1; ++i)
+    {
+      double offsetX = radiusS * cos(theta);
+      double offsetY = radiusS * sin(theta);
+      double pointX = centerS.GetX() + offsetX;
+      double pointY = centerS.GetY() + offsetY;
+      chain.push_back(ScenePoint2D(pointX, pointY));
+      theta += angleIncr;
+    }
+  }
+#endif
+
+  void AddCircle(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       radiusS,
+    const int           numSubdivisions)
+  {
+    //ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
+    //TODO: take DPI into account
+
+    // TODO: automatically compute the number for segments for smooth 
+    // display based on the radius in pixels.
+
+    chain.clear();
+    chain.reserve(numSubdivisions);
+
+    double angleIncr = (2.0 * g_pi)
+      / static_cast<double>(numSubdivisions);
+
+    double theta = 0;
+    for (int i = 0; i < numSubdivisions; ++i)
+    {
+      double offsetX = radiusS * cos(theta);
+      double offsetY = radiusS * sin(theta);
+      double pointX = centerS.GetX() + offsetX;
+      double pointY = centerS.GetY() + offsetY;
+      chain.push_back(ScenePoint2D(pointX, pointY));
+      theta += angleIncr;
+    }
+  }
+
+  double NormalizeAngle(double angle)
+  {
+    double retAngle = angle;
+    while (retAngle < -1.0*g_pi)
+      retAngle += 2 * g_pi;
+    while (retAngle >= g_pi)
+      retAngle -= 2 * g_pi;
+    return retAngle;
+  }
+
+  double MeasureAngle(const ScenePoint2D& p1, const ScenePoint2D& c, const ScenePoint2D& p2)
+  {
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    double delta = p2cAngle - p1cAngle;
+    return NormalizeAngle(delta);
+  }
+
+
+#if 0
+  void AddEllipse(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       halfHAxis,
+    const double&       halfVAxis)
+  {
+    chain.clear();
+    chain.reserve(4);
+    ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
+    //TODO: take DPI into account
+    double handleLX = centerC.GetX() - sideLength / 2;
+    double handleTY = centerC.GetY() - sideLength / 2;
+    double handleRX = centerC.GetX() + sideLength / 2;
+    double handleBY = centerC.GetY() + sideLength / 2;
+    ScenePoint2D LTC(handleLX, handleTY);
+    ScenePoint2D RTC(handleRX, handleTY);
+    ScenePoint2D RBC(handleRX, handleBY);
+    ScenePoint2D LBC(handleLX, handleBY);
+
+    ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
+
+    chain.push_back(startLT);
+    chain.push_back(startRT);
+    chain.push_back(startRB);
+    chain.push_back(startLB);
+}
+#endif
+
+
+  namespace
+  {
+    /**
+    Helper function for outlined text rendering
+    */
+    TextSceneLayer* GetOutlineTextLayer(
+      Scene2D& scene, int baseLayerIndex, int index)
+    {
+      assert(scene.HasLayer(baseLayerIndex));
+      assert(index >= 0);
+      assert(index < 5);
+
+      ISceneLayer * layer = &(scene.GetLayer(baseLayerIndex + index));
+      TextSceneLayer * concreteLayer = dynamic_cast<TextSceneLayer*>(layer);
+      assert(concreteLayer != NULL);
+      return concreteLayer;
+    }
+  }
+   
+  void SetTextLayerOutlineProperties(
+    Scene2D& scene, int baseLayerIndex, const char* text, ScenePoint2D p)
+  {
+    double xoffsets[5] = { 2, 0, -2, 0, 0 };
+    double yoffsets[5] = { 0, -2, 0, 2, 0 };
+
+    // get the scaling factor 
+    const double pixelToScene =
+      scene.GetCanvasToSceneTransform().ComputeZoom();
+
+    for (int i = 0; i < 5; ++i)
+    {
+      TextSceneLayer* textLayer = GetOutlineTextLayer(scene, baseLayerIndex, i);
+      textLayer->SetText(text);
+
+      if (i == 4)
+        textLayer->SetColor(0, 223, 81);
+      else
+        textLayer->SetColor(0, 56, 21);
+
+      ScenePoint2D textAnchor;
+      //GetPositionOnBisectingLine(
+      //  textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene);
+      textLayer->SetPosition(
+        p.GetX() + xoffsets[i] * pixelToScene,
+        p.GetY() + yoffsets[i] * pixelToScene);
+    }
+  }
+
+
+
+
+
+
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureToolsToolbox.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,187 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <Framework/Scene2D/PolylineSceneLayer.h>
+#include <Framework/Scene2D/Scene2D.h>
+
+namespace OrthancStone
+{
+
+  /**
+  This function will create a square around the center point supplied in
+  scene coordinates, with a side length given in canvas coordinates. The
+  square sides are parallel to the canvas boundaries.
+  */
+  void AddSquare(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       sideLength);
+
+
+  /**
+    Creates an arc centered on c that goes
+    - from a point r1:
+      - so that r1 belongs to the p1,c line
+      - so that the distance from c to r1 equals radius
+    - to a point r2:
+      - so that r2 belongs to the p2,c line
+      - so that the distance from c to r2 equals radius
+    - that follows the shortest among the two possible paths
+
+    Warning: the existing chain content will be wiped out.
+  */
+  void AddShortestArc(
+      PolylineSceneLayer::Chain&  chain
+    , const Scene2D&              scene
+    , const ScenePoint2D&         p1
+    , const ScenePoint2D&         c
+    , const ScenePoint2D&         p2
+    , const double&               radiusS
+    , const int                   subdivisionsCount = 63);
+
+  /**
+    Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from 
+    start angle to end angle, by following the shortest arc.
+
+    Warning: the existing chain content will be wiped out.
+  */
+  void AddShortestArc(
+      PolylineSceneLayer::Chain&  chain
+    , const Scene2D&              scene
+    , const ScenePoint2D&         centerS
+    , const double&               radiusS
+    , const double                startAngleRad
+    , const double                endAngleRad
+    , const int                   subdivisionsCount = 63);
+
+#if 0
+  /**
+    Creates an arc centered on c that goes
+    - from a point r1:
+      - so that r1 belongs to the p1,c line
+      - so that the distance from c to r1 equals radius
+    - to a point r2:
+      - so that r2 belongs to the p2,c line
+      - so that the distance from c to r2 equals radius
+
+    if clockwise is true, the arc is drawn from r1 to r2 with increasing 
+    angle values. Otherwise, the angle values decrease.
+
+    Warning: the existing chain content will be wiped out.
+  */
+
+  void AddArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&             scene
+    , const ScenePoint2D&        p1
+    , const ScenePoint2D&        c
+    , const ScenePoint2D&        p2
+    , const double&              radiusS
+    , const bool                 clockwise
+    , const int                  subdivisionsCount = 63);
+ 
+  /**
+    Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from 
+    start angle to end angle with the supplied radius.
+
+    if clockwise is true, the arc is drawn from start to end by increasing the
+    angle values.
+
+    Otherwise, the angle value decreases from start to end.
+
+    Warning: the existing chain content will be wiped out.
+  */
+  void AddArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&      scene
+    , const ScenePoint2D& centerS
+    , const double&       radiusS
+    , const double        startAngleRad
+    , const double        endAngleRad
+    , const bool          clockwise
+    , const int           subdivisionsCount = 63);
+#endif
+  /**
+    Creates a circle (closed curve) with "numSubdivisions"
+    (N points)
+
+    Warning: the existing chain content will be wiped out.
+  */
+  void AddCircle(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       radiusS,
+    const int           numSubdivisions = 63);
+
+  /**
+    Adds or subtracts 2*pi as many times as need to shift the specified
+    angle to a value such as: -pi <= value < pi
+   */
+  double NormalizeAngle(double angle);
+
+  /**
+    Returns the angle magnitude between the p1,c and p2,c lines. 
+    The returned angle is between 0 and 2*pi
+
+    If the angle is between 0 and pi, this means that the shortest arc 
+    from p1 to p2 is clockwise.
+
+    If the angle is between pi and 2*pi, this means that the shortest arc
+    from p1 to p2 is COUNTERclockwise.
+
+  */
+  double MeasureAngle(
+      const ScenePoint2D& p1
+    , const ScenePoint2D& c
+    , const ScenePoint2D& p2);
+
+  /**
+  RadiansToDegrees
+  */
+  double RadiansToDegrees(double angleRad);
+
+  /**
+  This function will return the coordinates of a point that:
+  - belongs to the two bisecting lines of the p1 c p2 angle.
+  - is a distance d from c.
+  Among the four possible points, the one returned will be the one belonging
+  to the *smallest* half-plane defined by the [c,p1[ and [c,p2[ half-lines.
+  */
+  void GetPositionOnBisectingLine(
+      ScenePoint2D&       result
+    , const ScenePoint2D& p1
+    , const ScenePoint2D& c
+    , const ScenePoint2D& p2
+    , const double d);
+
+
+  /**
+  This helper is used when drawing text with an outline.
+  It set the properties for several text layers at once : first the 
+  four outline layers, with a position shift and then the actual main text 
+  layer.
+
+  The five text layers are supposed to already exist in the scene, starting
+  from layerIndex, up to (and not including) layerIndex+5. 
+  */
+  void SetTextLayerOutlineProperties(
+    Scene2D& scene, int baseLayerIndex, const char* text, ScenePoint2D p);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureTrackers.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,66 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureTrackers.h"
+#include <Core/OrthancException.h>
+
+using namespace Orthanc;
+
+namespace OrthancStone
+{
+
+  CreateMeasureTracker::CreateMeasureTracker(ViewportControllerWPtr controllerW)
+    : controllerW_(controllerW)
+    , alive_(true)
+    , commitResult_(true)
+  {
+  }
+
+  void CreateMeasureTracker::Cancel()
+  {
+    commitResult_ = false;
+    alive_ = false;
+  }
+
+  bool CreateMeasureTracker::IsAlive() const
+  {
+    return alive_;
+  }
+
+  CreateMeasureTracker::~CreateMeasureTracker()
+  {
+    // if the tracker completes successfully, we add the command
+    // to the undo stack
+
+    // otherwise, we simply undo it
+    if (commitResult_)
+      controllerW_.lock()->PushCommand(command_);
+    else
+      command_->Undo();
+  }
+
+  OrthancStone::Scene2DPtr CreateMeasureTracker::GetScene()
+  {
+    return controllerW_.lock()->GetScene();
+  }
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureTrackers.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,54 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IFlexiblePointerTracker.h"
+#include "../../Framework/Scene2D/Scene2D.h"
+#include "../../Framework/Scene2D/PointerEvent.h"
+
+#include "MeasureTools.h"
+#include "MeasureCommands.h"
+
+#include <vector>
+
+namespace OrthancStone
+{
+  class CreateMeasureTracker : public IFlexiblePointerTracker
+  {
+  public:
+    virtual void Cancel() ORTHANC_OVERRIDE;
+    virtual bool IsAlive() const ORTHANC_OVERRIDE;
+  protected:
+    CreateMeasureTracker(ViewportControllerWPtr controllerW);
+
+    ~CreateMeasureTracker();
+  
+  protected:
+    CreateMeasureCommandPtr         command_;
+    ViewportControllerWPtr          controllerW_;
+    bool                            alive_;
+    Scene2DPtr                      GetScene();
+
+  private:
+    bool                            commitResult_;
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/OneGesturePointerTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,71 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "OneGesturePointerTracker.h"
+
+#include <Core/OrthancException.h>
+
+#include <Framework/StoneException.h>
+
+using namespace Orthanc;
+
+namespace OrthancStone
+{
+  OneGesturePointerTracker::OneGesturePointerTracker(
+    ViewportControllerWPtr controllerW)
+    : controllerW_(controllerW)
+    , alive_(true)
+    , currentTouchCount_(1)
+  {
+  }
+
+  void OneGesturePointerTracker::PointerUp(const PointerEvent& event)
+  {
+    // pointer up is only called for the LAST up event in case of a multi-touch
+    // gesture
+    ORTHANC_ASSERT(currentTouchCount_ > 0, "Wrong state in tracker");
+    currentTouchCount_--;
+    LOG(INFO) << "currentTouchCount_ becomes: " << currentTouchCount_;
+    if (currentTouchCount_ == 0)
+    {
+      LOG(INFO) << "currentTouchCount_ == 0 --> alive_ = false";
+      alive_ = false;
+    }
+  }
+
+  void OneGesturePointerTracker::PointerDown(const PointerEvent& event)
+  {
+    // additional touches are not taken into account but we need to count 
+    // the number of active touches
+    currentTouchCount_++;
+    LOG(INFO) << "currentTouchCount_ becomes: " << currentTouchCount_;
+  }
+
+  bool OneGesturePointerTracker::IsAlive() const
+  {
+    return alive_;
+  }
+
+  ViewportControllerPtr OneGesturePointerTracker::GetController()
+  {
+    return controllerW_.lock();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/OneGesturePointerTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,56 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IFlexiblePointerTracker.h"
+
+namespace OrthancStone
+{
+  /**
+  This base is class allows to write simple trackers that deal with single 
+  drag gestures with only one touch. It is *not* suitable for multi-touch and
+  multi-state trackers where various mouse operations need to be handled.
+
+  In order to write such a tracker:
+  - subclass this class
+  - you may store the initial click/touch position in the constructor
+  - implement PointerMove to react to pointer/touch events
+  - implement Cancel to restore the state at initial tracker creation time
+
+  */
+  class OneGesturePointerTracker : public IFlexiblePointerTracker
+  {
+  public:
+    OneGesturePointerTracker(ViewportControllerWPtr controllerW);
+    virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual bool IsAlive() const ORTHANC_OVERRIDE;
+  
+  protected:
+    ViewportControllerPtr  GetController();
+
+  private:
+    ViewportControllerWPtr controllerW_;
+    bool                   alive_;
+    int                    currentTouchCount_;
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/PointerTypes.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,81 @@
+/**
+ * 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 <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <vector>
+
+namespace OrthancStone
+{
+  class Scene2D;
+  typedef boost::shared_ptr<Scene2D> Scene2DPtr;
+
+  typedef boost::weak_ptr<Scene2D> Scene2DWPtr;
+
+  class MeasureTool;
+  typedef boost::shared_ptr<MeasureTool>
+    MeasureToolPtr;
+  typedef boost::weak_ptr<MeasureTool>
+    MeasureToolWPtr;
+
+  class LineMeasureTool;
+  typedef boost::shared_ptr<LineMeasureTool>
+    LineMeasureToolPtr;
+
+  class AngleMeasureTool;
+  typedef boost::shared_ptr<AngleMeasureTool>
+    AngleMeasureToolPtr;
+
+  class IPointerTracker;
+  typedef boost::shared_ptr<IPointerTracker>
+    PointerTrackerPtr;
+
+  class IFlexiblePointerTracker;
+  typedef boost::shared_ptr<IFlexiblePointerTracker>
+    FlexiblePointerTrackerPtr;
+
+  typedef boost::shared_ptr<LineMeasureTool>
+    LineMeasureToolPtr;
+
+  class CreateMeasureCommand;
+  typedef boost::shared_ptr<CreateMeasureCommand>
+    CreateMeasureCommandPtr;
+
+  class CreateLineMeasureCommand;
+  typedef boost::shared_ptr<CreateLineMeasureCommand>
+    CreateLineMeasureCommandPtr;
+
+  class CreateAngleMeasureCommand;
+  typedef boost::shared_ptr<CreateAngleMeasureCommand>
+    CreateAngleMeasureCommandPtr;
+
+
+  typedef boost::shared_ptr<Scene2D> Scene2DPtr;
+
+  class TrackerCommand;
+  typedef boost::shared_ptr<TrackerCommand> TrackerCommandPtr;
+
+  class ViewportController;
+  typedef boost::shared_ptr<ViewportController> ViewportControllerPtr;
+  typedef boost::weak_ptr<ViewportController> ViewportControllerWPtr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/ViewportController.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,137 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ViewportController.h"
+#include "MeasureCommands.h"
+
+#include <Framework/StoneException.h>
+
+#include <boost/make_shared.hpp>
+
+using namespace Orthanc;
+
+namespace OrthancStone
+{
+  ViewportController::ViewportController(MessageBroker& broker)
+    : IObservable(broker)
+    , numAppliedCommands_(0)
+  {
+    scene_ = boost::make_shared<Scene2D>();
+  }
+
+  Scene2DPtr ViewportController::GetScene()
+  {
+    return scene_;
+  }
+
+  bool ViewportController::HandlePointerEvent(PointerEvent e)
+  {
+    throw StoneException(ErrorCode_NotImplemented);
+  }
+
+  std::vector<MeasureToolPtr> ViewportController::HitTestMeasureTools(
+    ScenePoint2D p)
+  {
+    std::vector<MeasureToolPtr> ret;
+    
+
+    //for (size_t i = 0; i < measureTools_.size(); ++i)
+    //{
+
+    //}
+    return ret;
+  }
+
+  const OrthancStone::AffineTransform2D& ViewportController::GetCanvasToSceneTransform() const
+  {
+    return scene_->GetCanvasToSceneTransform();
+  }
+
+  const OrthancStone::AffineTransform2D& ViewportController::GetSceneToCanvasTransform() const
+  {
+    return scene_->GetSceneToCanvasTransform();
+  }
+
+  void ViewportController::SetSceneToCanvasTransform(
+    const AffineTransform2D& transform)
+  {
+    scene_->SetSceneToCanvasTransform(transform);
+    BroadcastMessage(SceneTransformChanged(*this));
+  }
+
+  void ViewportController::FitContent(
+    unsigned int canvasWidth, unsigned int canvasHeight)
+  {
+    scene_->FitContent(canvasWidth, canvasHeight);
+    BroadcastMessage(SceneTransformChanged(*this));
+  }
+
+  void ViewportController::PushCommand(TrackerCommandPtr command)
+  {
+    commandStack_.erase(
+      commandStack_.begin() + numAppliedCommands_,
+      commandStack_.end());
+    
+    ORTHANC_ASSERT(std::find(commandStack_.begin(), commandStack_.end(), command) 
+      == commandStack_.end(), "Duplicate command");
+    commandStack_.push_back(command);
+    numAppliedCommands_++;
+  }
+
+  void ViewportController::Undo()
+  {
+    ORTHANC_ASSERT(CanUndo(), "");
+    commandStack_[numAppliedCommands_-1]->Undo();
+    numAppliedCommands_--;
+  }
+
+  void ViewportController::Redo()
+  {
+    ORTHANC_ASSERT(CanRedo(), "");
+    commandStack_[numAppliedCommands_]->Redo();
+    numAppliedCommands_++;
+  }
+
+  bool ViewportController::CanUndo() const
+  {
+    return numAppliedCommands_ > 0;
+  }
+
+  bool ViewportController::CanRedo() const
+  {
+    return numAppliedCommands_ < commandStack_.size();
+  }
+
+  void ViewportController::AddMeasureTool(MeasureToolPtr measureTool)
+  {
+    ORTHANC_ASSERT(std::find(measureTools_.begin(), measureTools_.end(), measureTool)
+      == measureTools_.end(), "Duplicate measure tool");
+    measureTools_.push_back(measureTool);
+  }
+
+  void ViewportController::RemoveMeasureTool(MeasureToolPtr measureTool)
+  {
+    ORTHANC_ASSERT(std::find(measureTools_.begin(), measureTools_.end(), measureTool)
+      != measureTools_.end(), "Measure tool not found");
+    measureTools_.push_back(measureTool);
+  }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/ViewportController.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,136 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "PointerTypes.h"
+
+#include <Framework/Scene2D/Scene2D.h>
+#include <Framework/Scene2D/PointerEvent.h>
+#include <Framework/Scene2DViewport/IFlexiblePointerTracker.h>
+
+#include <stack>
+
+namespace OrthancStone
+{
+  /**
+  This object is responsible for hosting a scene, responding to messages from
+  the model and updating the scene accordingly.
+
+  It contains the list of active measuring tools as well as the stack
+  where measuring tool commands are stored.
+
+  The active tracker is also stored in the viewport controller.
+
+  Each canvas or other GUI area where we want to display a 2D image, either 
+  directly or through slicing must be assigned a ViewportController.
+  */
+  class ViewportController : public IObservable
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, \
+      SceneTransformChanged, ViewportController);
+
+    ViewportController(MessageBroker& broker);
+
+    Scene2DPtr GetScene();
+
+    /** 
+    This method is called by the GUI system and should update/delete the
+    current tracker
+    */
+    bool HandlePointerEvent(PointerEvent e);
+
+    /**
+    This method returns the list of measure tools containing the supplied point
+    (in scene coords). A tracker can then be requested from the chosen 
+    measure tool, if needed
+    */
+    std::vector<MeasureToolPtr> HitTestMeasureTools(ScenePoint2D p);
+
+    /**
+    With this method, the object takes ownership of the supplied tracker and
+    updates it according to user interaction
+    */
+    void SetActiveTracker(FlexiblePointerTrackerPtr tracker);
+
+    /** Forwarded to the underlying scene */
+    const AffineTransform2D& GetCanvasToSceneTransform() const;
+
+    /** Forwarded to the underlying scene */
+    const AffineTransform2D& GetSceneToCanvasTransform() const;
+
+    /** Forwarded to the underlying scene, and broadcasted to the observers */
+    void SetSceneToCanvasTransform(const AffineTransform2D& transform);
+
+    /** Forwarded to the underlying scene, and broadcasted to the observers */
+    void FitContent(unsigned int canvasWidth, unsigned int canvasHeight);
+
+    /** 
+    Stores a command : 
+    - this first trims the undo stack to keep the first numAppliedCommands_ 
+    - then it adds the supplied command at the top of the undo stack
+
+    In other words, when a new command is pushed, all the undone (and not 
+    redone) commands are removed.
+    */
+    void PushCommand(TrackerCommandPtr command);
+
+    /**
+    Undoes the command at the top of the undo stack, or throws if there is no
+    command to undo.
+    You can check "CanUndo" first to protect against extraneous redo.
+    */
+    void Undo();
+
+    /**
+    Redoes the command that is just above the last applied command in the undo
+    stack or throws if there is no command to redo. 
+    You can check "CanRedo" first to protect against extraneous redo.
+    */
+    void Redo();
+
+    /** selfexpl */
+    bool CanUndo() const;
+
+    /** selfexpl */
+    bool CanRedo() const;
+
+    /** Adds a new measure tool */
+    void AddMeasureTool(MeasureToolPtr measureTool);
+
+    /** Removes a measure tool or throws if it cannot be found */
+    void RemoveMeasureTool(MeasureToolPtr measureTool);
+
+  private:
+    std::vector<TrackerCommandPtr> commandStack_;
+    
+    /**
+    This is always between >= 0 and <= undoStack_.size() and gives the 
+    position where the controller is in the undo stack. 
+    - If numAppliedCommands_ > 0, one can undo
+    - If numAppliedCommands_ < numAppliedCommands_.size(), one can redo
+    */
+    size_t                         numAppliedCommands_;
+    std::vector<MeasureToolPtr>    measureTools_;
+    Scene2DPtr                     scene_;
+    FlexiblePointerTrackerPtr      tracker_;
+  };
+}
--- a/Framework/SmartLoader.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/SmartLoader.cpp	Tue May 21 13:25:58 2019 +0200
@@ -28,7 +28,7 @@
 #include "Framework/Layers/FrameRenderer.h"
 #include "Core/Logging.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   enum CachedSliceStatus
   {
@@ -53,8 +53,8 @@
 
       virtual ILayerRenderer* CreateRenderer() const
       {
-        bool isFull = (that_.effectiveQuality_ == SliceImageQuality_FullPng ||
-                       that_.effectiveQuality_ == SliceImageQuality_FullPam);
+        bool isFull = (that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPng ||
+                       that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPam);
 
         return FrameRenderer::CreateRenderer(*that_.image_, *that_.slice_, isFull);
       }
@@ -63,11 +63,11 @@
     unsigned int                    sliceIndex_;
     std::auto_ptr<Slice>            slice_;
     boost::shared_ptr<Orthanc::ImageAccessor>   image_;
-    SliceImageQuality               effectiveQuality_;
+    OrthancStone::SliceImageQuality               effectiveQuality_;
     CachedSliceStatus               status_;
 
   public:
-    CachedSlice(MessageBroker& broker) :
+    CachedSlice(OrthancStone::MessageBroker& broker) :
     IVolumeSlicer(broker)
     {
     }
@@ -76,15 +76,15 @@
     {
     }
 
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice)
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice)
     {
       // TODO: viewportSlice is not used !!!!
       slice_->GetExtent(points);
       return true;
     }
 
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice)
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
     {
       // TODO: viewportSlice is not used !!!!
 
@@ -118,11 +118,11 @@
   };
 
 
-  SmartLoader::SmartLoader(MessageBroker& broker,  
+  SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker,  
                            OrthancApiClient& orthancApiClient) :
     IObservable(broker),
     IObserver(broker),
-    imageQuality_(SliceImageQuality_FullPam),
+    imageQuality_(OrthancStone::SliceImageQuality_FullPam),
     orthancApiClient_(orthancApiClient)
   {
   }
@@ -152,9 +152,9 @@
     {
       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));
+      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
+      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
+      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
       dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
     }
 
@@ -169,7 +169,7 @@
     }
     else
     {
-      throw StoneException(ErrorCode_CanOnlyAddOneLayerAtATime);
+      throw OrthancStone::StoneException(OrthancStone::ErrorCode_CanOnlyAddOneLayerAtATime);
     }
 
     if (cachedSlice != NULL)
@@ -201,9 +201,9 @@
     std::auto_ptr<IVolumeSlicer> layerSource(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));
+    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
+    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
+    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
     dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
 
     // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache
--- a/Framework/SmartLoader.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/SmartLoader.h	Tue May 21 13:25:58 2019 +0200
@@ -26,11 +26,11 @@
 #include "Messages/IObservable.h"
 #include "Toolbox/OrthancApiClient.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class SliceViewerWidget;
 
-  class SmartLoader : public IObservable, public IObserver
+  class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
   {
     class CachedSlice;
 
@@ -41,17 +41,17 @@
     typedef std::map<std::string, boost::shared_ptr<IVolumeSlicer> > PreloadingInstances;
     PreloadingInstances preloadingInstances_;
 
-    SliceImageQuality     imageQuality_;
+    OrthancStone::SliceImageQuality     imageQuality_;
     OrthancApiClient&     orthancApiClient_;
 
   public:
-    SmartLoader(MessageBroker& broker, OrthancApiClient& orthancApiClient);  // TODO: add maxPreloadStorageSizeInBytes
+    SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient);  // TODO: add maxPreloadStorageSizeInBytes
 
 //    void PreloadStudy(const std::string studyId);
 //    void PreloadSeries(const std::string seriesId);
     void PreloadSlice(const std::string instanceId, unsigned int frame);
 
-    void SetImageQuality(SliceImageQuality imageQuality) { imageQuality_ = imageQuality; }
+    void SetImageQuality(OrthancStone::SliceImageQuality imageQuality) { imageQuality_ = imageQuality; }
 
     void SetFrameInWidget(SliceViewerWidget& sliceViewer, size_t layerIndex, const std::string& instanceId, unsigned int frame);
 
--- a/Framework/StoneException.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/StoneException.h	Tue May 21 13:25:58 2019 +0200
@@ -113,3 +113,13 @@
 
 }
 
+// See https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-multi-stmts
+// (or google "Multiple lines macro C++ faq lite" if link is dead)
+#define ORTHANC_ASSERT(cond,streamChainMessage) \
+    if (!(cond)) { \
+      std::stringstream sst; \
+      sst << "Assertion failed. Condition = \"" #cond "\" Message = \"" << streamChainMessage << "\""; \
+      std::string sstr = sst.str(); \
+      throw OrthancException(ErrorCode_InternalError,sstr.c_str()); \
+    } else (void)0
+
--- a/Framework/Toolbox/BaseWebService.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/BaseWebService.cpp	Tue May 21 13:25:58 2019 +0200
@@ -26,20 +26,20 @@
 #include "Platforms/Generic/IOracleCommand.h"
 #include <boost/shared_ptr.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
 
 
   class BaseWebService::BaseWebServicePayload : public Orthanc::IDynamicObject
   {
   private:
-    std::auto_ptr< MessageHandler<IWebService::HttpRequestSuccessMessage> >   userSuccessHandler_;
-    std::auto_ptr< MessageHandler<IWebService::HttpRequestErrorMessage> >     userFailureHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> >   userSuccessHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >     userFailureHandler_;
     std::auto_ptr< Orthanc::IDynamicObject>                                   userPayload_;
 
   public:
-    BaseWebServicePayload(MessageHandler<IWebService::HttpRequestSuccessMessage>* userSuccessHandler,
-                          MessageHandler<IWebService::HttpRequestErrorMessage>* userFailureHandler,
+    BaseWebServicePayload(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* userSuccessHandler,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* userFailureHandler,
                           Orthanc::IDynamicObject* userPayload) :
       userSuccessHandler_(userSuccessHandler),
       userFailureHandler_(userFailureHandler),
@@ -83,17 +83,17 @@
   void BaseWebService::GetAsync(const std::string& uri,
                                 const HttpHeaders& headers,
                                 Orthanc::IDynamicObject* payload  /* takes ownership */,
-                                MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                                MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+                                OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                                OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
                                 unsigned int timeoutInSeconds)
   {
     if (cache_.find(uri) == cache_.end())
     {
       GetAsyncInternal(uri, headers,
                        new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered
-                       new Callable<BaseWebService, IWebService::HttpRequestSuccessMessage>
+                       new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestSuccessMessage>
                        (*this, &BaseWebService::CacheAndNotifyHttpSuccess),
-                       new Callable<BaseWebService, IWebService::HttpRequestErrorMessage>
+                       new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestErrorMessage>
                        (*this, &BaseWebService::NotifyHttpError),
                        timeoutInSeconds);
     }
--- a/Framework/Toolbox/BaseWebService.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/BaseWebService.h	Tue May 21 13:25:58 2019 +0200
@@ -26,11 +26,11 @@
 #include <string>
 #include <map>
 
-namespace OrthancStone
+namespace Deprecated
 {
   // This is an intermediate of IWebService that implements some caching on
   // the HTTP GET requests
-  class BaseWebService : public IWebService, public IObserver
+  class BaseWebService : public IWebService, public OrthancStone::IObserver
   {
   public:
     class CachedHttpRequestSuccessMessage
@@ -85,7 +85,7 @@
 
   public:
 
-    BaseWebService(MessageBroker& broker) :
+    BaseWebService(OrthancStone::MessageBroker& broker) :
       IWebService(broker),
       IObserver(broker),
       cacheEnabled_(true)
@@ -104,21 +104,21 @@
     virtual void GetAsync(const std::string& uri,
                           const HttpHeaders& headers,
                           Orthanc::IDynamicObject* payload  /* takes ownership */,
-                          MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                          MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                           unsigned int timeoutInSeconds = 60);
 
   protected:
     virtual void GetAsyncInternal(const std::string& uri,
                           const HttpHeaders& headers,
                           Orthanc::IDynamicObject* payload  /* takes ownership */,
-                          MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                          MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                           unsigned int timeoutInSeconds = 60) = 0;
 
     virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
                                         Orthanc::IDynamicObject* payload, // takes ownership
-                                        MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback) = 0;
+                                        OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback) = 0;
 
   private:
     void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
--- a/Framework/Toolbox/DicomFrameConverter.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/DicomFrameConverter.cpp	Tue May 21 13:25:58 2019 +0200
@@ -28,7 +28,7 @@
 #include <Core/OrthancException.h>
 #include <Core/Toolbox.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   static const Orthanc::DicomTag IMAGE_TAGS[] =
   {
@@ -61,9 +61,9 @@
   {
     SetDefaultParameters();
 
-    Vector c, w;
-    if (LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
-        LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
+    OrthancStone::Vector c, w;
+    if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
+        OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
         c.size() > 0 && 
         w.size() > 0)
     {
--- a/Framework/Toolbox/DicomFrameConverter.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/DicomFrameConverter.h	Tue May 21 13:25:58 2019 +0200
@@ -27,7 +27,7 @@
 
 #include <memory>
 
-namespace OrthancStone
+namespace Deprecated
 {
   /**
    * This class is responsible for converting the pixel format of a
--- a/Framework/Toolbox/DownloadStack.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/DownloadStack.cpp	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 
 #include <cassert>
 
-namespace OrthancStone
+namespace Deprecated
 {
   bool DownloadStack::CheckInvariants() const
   {
@@ -77,8 +77,8 @@
     {
       for (size_t i = 0; i < size; i++)
       {
-        nodes_[i].prev_ = i - 1;
-        nodes_[i].next_ = i + 1;
+        nodes_[i].prev_ = static_cast<int>(i - 1);
+        nodes_[i].next_ = static_cast<int>(i + 1);
         nodes_[i].dequeued_ = false;
       }
 
--- a/Framework/Toolbox/DownloadStack.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/DownloadStack.h	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <vector>
 #include <boost/noncopyable.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class DownloadStack : public boost::noncopyable
   {
--- a/Framework/Toolbox/FiniteProjectiveCamera.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/FiniteProjectiveCamera.cpp	Tue May 21 13:25:58 2019 +0200
@@ -316,7 +316,7 @@
     LOG(WARNING) << "Output pixel format: " << Orthanc::EnumerationToString(target.GetFormat());
 
     std::auto_ptr<OrthancStone::ParallelSlices> slices(source.GetGeometry(projection));
-    const OrthancStone::Vector pixelSpacing = source.GetVoxelDimensions(projection);
+    const OrthancStone::Vector pixelSpacing = source.GetGeometry().GetVoxelDimensions(projection);
     const unsigned int targetWidth = target.GetWidth();
     const unsigned int targetHeight = target.GetHeight();
 
@@ -360,7 +360,8 @@
 
             // Read and accumulate the value of the pixel
             float pixel;
-            if (pixelReader.GetFloatValue(pixel, ix, iy))
+            if (pixelReader.GetFloatValue(
+              pixel, static_cast<float>(ix), static_cast<float>(iy)))
             {
               if (MIP)
               {
--- a/Framework/Toolbox/IDelayedCallExecutor.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/IDelayedCallExecutor.h	Tue May 21 13:25:58 2019 +0200
@@ -30,18 +30,18 @@
 #include <string>
 #include <map>
 
-namespace OrthancStone
+namespace Deprecated
 {
   // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript).
   class IDelayedCallExecutor : public boost::noncopyable
   {
   protected:
-    MessageBroker& broker_;
+    OrthancStone::MessageBroker& broker_;
     
   public:
     ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage);
 
-    IDelayedCallExecutor(MessageBroker& broker) :
+    IDelayedCallExecutor(OrthancStone::MessageBroker& broker) :
       broker_(broker)
     {
     }
@@ -52,7 +52,7 @@
     }
 
     
-    virtual void Schedule(MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
-                         unsigned int timeoutInMs = 1000) = 0;
+    virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
+                          unsigned int timeoutInMs = 1000) = 0;
   };
 }
--- a/Framework/Toolbox/IWebService.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/IWebService.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <Core/OrthancException.h>
 
 
-namespace OrthancStone
+namespace Deprecated
 {
   const Orthanc::IDynamicObject&
   IWebService::HttpRequestSuccessMessage::GetPayload() const
--- a/Framework/Toolbox/IWebService.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/IWebService.h	Tue May 21 13:25:58 2019 +0200
@@ -30,7 +30,7 @@
 #include <string>
 #include <map>
 
-namespace OrthancStone
+namespace Deprecated
 {
   // The IWebService performs HTTP requests.
   // Since applications can run in native or WASM environment and, since
@@ -40,12 +40,12 @@
   class IWebService : public boost::noncopyable
   {
   protected:
-    MessageBroker& broker_;
+    OrthancStone::MessageBroker& broker_;
     
   public:
     typedef std::map<std::string, std::string> HttpHeaders;
 
-    class HttpRequestSuccessMessage : public IMessage
+    class HttpRequestSuccessMessage : public OrthancStone::IMessage
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
 
@@ -99,7 +99,7 @@
     };
     
 
-    class HttpRequestErrorMessage : public IMessage
+    class HttpRequestErrorMessage : public OrthancStone::IMessage
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
 
@@ -129,7 +129,7 @@
     };
 
 
-    IWebService(MessageBroker& broker) :
+    IWebService(OrthancStone::MessageBroker& broker) :
       broker_(broker)
     {
     }
@@ -144,23 +144,23 @@
     virtual void GetAsync(const std::string& uri,
                           const HttpHeaders& headers,
                           Orthanc::IDynamicObject* payload  /* takes ownership */,
-                          MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                          MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                           unsigned int timeoutInSeconds = 60) = 0;
 
     virtual void PostAsync(const std::string& uri,
                            const HttpHeaders& headers,
                            const std::string& body,
                            Orthanc::IDynamicObject* payload  /* takes ownership */,
-                           MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                           MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                           OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                            unsigned int timeoutInSeconds = 60) = 0;
 
     virtual void DeleteAsync(const std::string& uri,
                              const HttpHeaders& headers,
                              Orthanc::IDynamicObject* payload  /* takes ownership */,
-                             MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                             MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                             OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                             OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                              unsigned int timeoutInSeconds = 60) = 0;
   };
 }
--- a/Framework/Toolbox/OrientedBoundingBox.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/OrientedBoundingBox.cpp	Tue May 21 13:25:58 2019 +0200
@@ -37,8 +37,8 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize);      
     }
 
-    const CoordinateSystem3D& geometry = image.GetAxialGeometry();
-    Vector dim = image.GetVoxelDimensions(VolumeProjection_Axial);
+    const CoordinateSystem3D& geometry = image.GetGeometry().GetAxialGeometry();
+    Vector dim = image.GetGeometry().GetVoxelDimensions(VolumeProjection_Axial);
 
     u_ = geometry.GetAxisX();
     v_ = geometry.GetAxisY();
--- a/Framework/Toolbox/OrthancApiClient.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/OrthancApiClient.cpp	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const
   {
@@ -69,10 +69,10 @@
   class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject
   {
   private:
-    std::auto_ptr< MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
-    std::auto_ptr< MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
-    std::auto_ptr< MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
-    std::auto_ptr< MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
     std::auto_ptr< Orthanc::IDynamicObject >                               userPayload_;
 
     void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const
@@ -85,8 +85,8 @@
     }
     
   public:
-    WebServicePayload(MessageHandler<EmptyResponseReadyMessage>* handler,
-                      MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
+    WebServicePayload(OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                       Orthanc::IDynamicObject* userPayload) :
       emptyHandler_(handler),
       failureHandler_(failureHandler),
@@ -98,8 +98,8 @@
       }
     }
 
-    WebServicePayload(MessageHandler<BinaryResponseReadyMessage>* handler,
-                      MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
+    WebServicePayload(OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                       Orthanc::IDynamicObject* userPayload) :
       binaryHandler_(handler),
       failureHandler_(failureHandler),
@@ -111,8 +111,8 @@
       }
     }
 
-    WebServicePayload(MessageHandler<JsonResponseReadyMessage>* handler,
-                      MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
+    WebServicePayload(OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                       Orthanc::IDynamicObject* userPayload) :
       jsonHandler_(handler),
       failureHandler_(failureHandler),
@@ -140,7 +140,7 @@
       else if (jsonHandler_.get() != NULL)
       {
         Json::Value response;
-        if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
+        if (OrthancStone::MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
         {
           jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage
                               (message.GetUri(), response, userPayload_.get()));
@@ -167,7 +167,7 @@
   };
 
 
-  OrthancApiClient::OrthancApiClient(MessageBroker& broker,
+  OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker,
                                      IWebService& web,
                                      const std::string& baseUrl) :
     IObservable(broker),
@@ -180,17 +180,17 @@
 
   void OrthancApiClient::GetJsonAsync(
       const std::string& uri,
-      MessageHandler<JsonResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload)
   {
     IWebService::HttpHeaders emptyHeaders;
     web_.GetAsync(baseUrl_ + uri,
                   emptyHeaders,
                   new WebServicePayload(successCallback, failureCallback, payload),
-                  new Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                   (*this, &OrthancApiClient::NotifyHttpSuccess),
-                  new Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                   (*this, &OrthancApiClient::NotifyHttpError));
   }
 
@@ -198,8 +198,8 @@
   void OrthancApiClient::GetBinaryAsync(
       const std::string& uri,
       const std::string& contentType,
-      MessageHandler<BinaryResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload)
   {
     IWebService::HttpHeaders headers;
@@ -210,17 +210,17 @@
   void OrthancApiClient::GetBinaryAsync(
       const std::string& uri,
       const IWebService::HttpHeaders& headers,
-      MessageHandler<BinaryResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload)
   {
     // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str());
 
     web_.GetAsync(baseUrl_ + uri, headers,
                   new WebServicePayload(successCallback, failureCallback, payload),
-                  new Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                   (*this, &OrthancApiClient::NotifyHttpSuccess),
-                  new Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                   (*this, &OrthancApiClient::NotifyHttpError));
   }
 
@@ -228,15 +228,15 @@
   void OrthancApiClient::PostBinaryAsyncExpectJson(
       const std::string& uri,
       const std::string& body,
-      MessageHandler<JsonResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload)
   {
     web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
                    new WebServicePayload(successCallback, failureCallback, payload),
-                   new Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                    (*this, &OrthancApiClient::NotifyHttpSuccess),
-                   new Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                    (*this, &OrthancApiClient::NotifyHttpError));
 
   }
@@ -251,27 +251,27 @@
   void OrthancApiClient::PostBinaryAsync(
       const std::string& uri,
       const std::string& body,
-      MessageHandler<EmptyResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload   /* takes ownership */)
   {
     web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
                    new WebServicePayload(successCallback, failureCallback, payload),
-                   new Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                    (*this, &OrthancApiClient::NotifyHttpSuccess),
-                   new Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                    (*this, &OrthancApiClient::NotifyHttpError));
   }
 
   void OrthancApiClient::PostJsonAsyncExpectJson(
       const std::string& uri,
       const Json::Value& data,
-      MessageHandler<JsonResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload)
   {
     std::string body;
-    MessagingToolbox::JsonToString(body, data);
+    OrthancStone::MessagingToolbox::JsonToString(body, data);
     return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload);
   }
 
@@ -280,33 +280,33 @@
       const Json::Value& data)
   {
     std::string body;
-    MessagingToolbox::JsonToString(body, data);
+    OrthancStone::MessagingToolbox::JsonToString(body, data);
     return PostBinaryAsync(uri, body);
   }
 
   void OrthancApiClient::PostJsonAsync(
       const std::string& uri,
       const Json::Value& data,
-      MessageHandler<EmptyResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload   /* takes ownership */)
   {
     std::string body;
-    MessagingToolbox::JsonToString(body, data);
+    OrthancStone::MessagingToolbox::JsonToString(body, data);
     return PostBinaryAsync(uri, body, successCallback, failureCallback, payload);
   }
 
   void OrthancApiClient::DeleteAsync(
       const std::string& uri,
-      MessageHandler<EmptyResponseReadyMessage>* successCallback,
-      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
       Orthanc::IDynamicObject* payload)
   {
     web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(),
                      new WebServicePayload(successCallback, failureCallback, payload),
-                     new Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                      (*this, &OrthancApiClient::NotifyHttpSuccess),
-                     new Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                      (*this, &OrthancApiClient::NotifyHttpError));
   }
 
--- a/Framework/Toolbox/OrthancApiClient.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/OrthancApiClient.h	Tue May 21 13:25:58 2019 +0200
@@ -28,14 +28,14 @@
 #include "../Messages/IObservable.h"
 #include "../Messages/Promise.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class OrthancApiClient :
-      public IObservable,
-      public IObserver
+      public OrthancStone::IObservable,
+      public OrthancStone::IObserver
   {
   public:
-    class JsonResponseReadyMessage : public IMessage
+    class JsonResponseReadyMessage : public OrthancStone::IMessage
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
 
@@ -73,7 +73,7 @@
     };
     
 
-    class BinaryResponseReadyMessage : public IMessage
+    class BinaryResponseReadyMessage : public OrthancStone::IMessage
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
 
@@ -119,7 +119,7 @@
     };
 
 
-    class EmptyResponseReadyMessage : public IMessage
+    class EmptyResponseReadyMessage : public OrthancStone::IMessage
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
 
@@ -158,7 +158,7 @@
     std::string   baseUrl_;
 
   public:
-    OrthancApiClient(MessageBroker& broker,
+    OrthancApiClient(OrthancStone::MessageBroker& broker,
                      IWebService& web,
                      const std::string& baseUrl);
     
@@ -170,36 +170,36 @@
 
     // schedule a GET request expecting a JSON response.
     void GetJsonAsync(const std::string& uri,
-                      MessageHandler<JsonResponseReadyMessage>* successCallback,
-                      MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                       Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a GET request expecting a binary response.
     void GetBinaryAsync(const std::string& uri,
                         const std::string& contentType,
-                        MessageHandler<BinaryResponseReadyMessage>* successCallback,
-                        MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                        OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                         Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a GET request expecting a binary response.
     void GetBinaryAsync(const std::string& uri,
                         const IWebService::HttpHeaders& headers,
-                        MessageHandler<BinaryResponseReadyMessage>* successCallback,
-                        MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                        OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                         Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a POST request expecting a JSON response.
     void PostBinaryAsyncExpectJson(const std::string& uri,
                                    const std::string& body,
-                                   MessageHandler<JsonResponseReadyMessage>* successCallback,
-                                   MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                                   OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+                                   OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                                    Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a POST request expecting a JSON response.
     void PostJsonAsyncExpectJson(const std::string& uri,
                                  const Json::Value& data,
-                                 MessageHandler<JsonResponseReadyMessage>* successCallback,
-                                 MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                                 OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+                                 OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                                  Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a POST request and don't mind the response.
@@ -209,8 +209,8 @@
     // schedule a POST request and don't expect any response.
     void PostJsonAsync(const std::string& uri,
                        const Json::Value& data,
-                       MessageHandler<EmptyResponseReadyMessage>* successCallback,
-                       MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                       OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+                       OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
 
@@ -221,14 +221,14 @@
     // schedule a POST request and don't expect any response.
     void PostBinaryAsync(const std::string& uri,
                          const std::string& body,
-                         MessageHandler<EmptyResponseReadyMessage>* successCallback,
-                         MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                         OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+                         OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                          Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a DELETE request expecting an empty response.
     void DeleteAsync(const std::string& uri,
-                     MessageHandler<EmptyResponseReadyMessage>* successCallback,
-                     MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                     OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+                     OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                      Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.cpp	Tue May 21 13:25:58 2019 +0200
@@ -68,7 +68,7 @@
 
 
 
-namespace OrthancStone
+namespace Deprecated
 {
   class OrthancSlicesLoader::Operation : public Orthanc::IDynamicObject
   {
@@ -78,7 +78,7 @@
     unsigned int       sliceIndex_;
     const Slice*       slice_;
     std::string        instanceId_;
-    SliceImageQuality  quality_;
+    OrthancStone::SliceImageQuality  quality_;
 
     Operation(Mode mode) :
       mode_(mode)
@@ -91,7 +91,7 @@
       return mode_;
     }
 
-    SliceImageQuality GetQuality() const
+    OrthancStone::SliceImageQuality GetQuality() const
     {
       assert(mode_ == Mode_LoadImage ||
              mode_ == Mode_LoadRawImage);
@@ -144,7 +144,7 @@
 
     static Operation* DownloadSliceImage(unsigned int  sliceIndex,
                                          const Slice&  slice,
-                                         SliceImageQuality quality)
+                                         OrthancStone::SliceImageQuality quality)
     {
       std::auto_ptr<Operation> tmp(new Operation(Mode_LoadImage));
       tmp->sliceIndex_ = sliceIndex;
@@ -159,7 +159,7 @@
       std::auto_ptr<Operation> tmp(new Operation(Mode_LoadRawImage));
       tmp->sliceIndex_ = sliceIndex;
       tmp->slice_ = &slice;
-      tmp->quality_ = SliceImageQuality_InternalRaw;
+      tmp->quality_ = OrthancStone::SliceImageQuality_InternalRaw;
       return tmp.release();
     }
 
@@ -231,7 +231,7 @@
       OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]);
       
       Orthanc::DicomMap dicom;
-      MessagingToolbox::ConvertDataset(dicom, dataset);
+      OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
       
       unsigned int frames;
       if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
@@ -244,7 +244,7 @@
         std::auto_ptr<Slice> slice(new Slice);
         if (slice->ParseOrthancFrame(dicom, instances[i], frame))
         {
-          CoordinateSystem3D geometry = slice->GetGeometry();
+          OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
           slices_.AddSlice(geometry, slice.release());
         }
         else
@@ -265,7 +265,7 @@
     OrthancPlugins::FullOrthancDataset dataset(tags);
     
     Orthanc::DicomMap dicom;
-    MessagingToolbox::ConvertDataset(dicom, dataset);
+    OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
 
     unsigned int frames;
     if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
@@ -280,7 +280,7 @@
       std::auto_ptr<Slice> slice(new Slice);
       if (slice->ParseOrthancFrame(dicom, instanceId, frame))
       {
-        CoordinateSystem3D geometry = slice->GetGeometry();
+        OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
         slices_.AddSlice(geometry, slice.release());
       }
       else
@@ -306,14 +306,14 @@
     state_ = State_GeometryReady;
     
     Orthanc::DicomMap dicom;
-    MessagingToolbox::ConvertDataset(dicom, dataset);
+    OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
     
     std::auto_ptr<Slice> slice(new Slice);
     if (slice->ParseOrthancFrame(dicom, instanceId, frame))
     {
       LOG(INFO) << "Loaded instance geometry " << instanceId;
 
-      CoordinateSystem3D geometry = slice->GetGeometry();
+      OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
       slices_.AddSlice(geometry, slice.release());
       
       BroadcastMessage(SliceGeometryReadyMessage(*this));
@@ -544,7 +544,7 @@
     
     float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
     
-    if (!LinearAlgebra::IsCloseToZero(scaling))
+    if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling))
     {
       float offset = static_cast<float>(stretchLow) / scaling;
       Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
@@ -639,10 +639,10 @@
   }
   
   
-  OrthancSlicesLoader::OrthancSlicesLoader(MessageBroker& broker,
+  OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
                                            OrthancApiClient& orthanc) :
-    IObservable(broker),
-    IObserver(broker),
+    OrthancStone::IObservable(broker),
+    OrthancStone::IObserver(broker),
     orthanc_(orthanc),
     state_(State_Initialization)
   {
@@ -659,8 +659,8 @@
     {
       state_ = State_LoadingGeometry;
       orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags",
-                            new Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSeriesGeometry),
-                            new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
+                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSeriesGeometry),
+                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
                             NULL);
     }
   }
@@ -678,8 +678,8 @@
       // Tag "3004-000c" is "Grid Frame Offset Vector", which is
       // mandatory to read RT DOSE, but is too long to be returned by default
       orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c",
-                            new Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseInstanceGeometry),
-                            new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
+                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseInstanceGeometry),
+                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
                             Operation::DownloadInstanceGeometry(instanceId));
     }
   }
@@ -697,8 +697,8 @@
       state_ = State_LoadingGeometry;
 
       orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags",
-                            new Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseFrameGeometry),
-                            new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
+                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseFrameGeometry),
+                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
                             Operation::DownloadFrameGeometry(instanceId, frame));
     }
   }
@@ -733,7 +733,7 @@
   
   
   bool OrthancSlicesLoader::LookupSlice(size_t& index,
-                                        const CoordinateSystem3D& plane) const
+                                        const OrthancStone::CoordinateSystem3D& plane) const
   {
     if (state_ != State_GeometryReady)
     {
@@ -771,16 +771,22 @@
     }
     
     orthanc_.GetBinaryAsync(uri, "image/png",
-                            new Callable<OrthancSlicesLoader, OrthancApiClient::BinaryResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSliceImagePng),
-                            new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnSliceImageError),
-                            Operation::DownloadSliceImage(index, slice, SliceImageQuality_FullPng));
-  }
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        OrthancApiClient::BinaryResponseReadyMessage>
+          (*this, &OrthancSlicesLoader::ParseSliceImagePng),
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        IWebService::HttpRequestErrorMessage>
+          (*this, &OrthancSlicesLoader::OnSliceImageError),
+      Operation::DownloadSliceImage(
+        static_cast<unsigned int>(index), slice, OrthancStone::SliceImageQuality_FullPng));
+}
   
   void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice,
                                                   size_t index)
   {
-    std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
-                       boost::lexical_cast<std::string>(slice.GetFrame()));
+    std::string uri = 
+      ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
+      boost::lexical_cast<std::string>(slice.GetFrame()));
 
     switch (slice.GetConverter().GetExpectedPixelFormat())
     {
@@ -801,30 +807,35 @@
     }
 
     orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap",
-                            new Callable<OrthancSlicesLoader, OrthancApiClient::BinaryResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSliceImagePam),
-                            new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnSliceImageError),
-                            Operation::DownloadSliceImage(index, slice, SliceImageQuality_FullPam));
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        OrthancApiClient::BinaryResponseReadyMessage>
+          (*this, &OrthancSlicesLoader::ParseSliceImagePam),
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        IWebService::HttpRequestErrorMessage>
+          (*this, &OrthancSlicesLoader::OnSliceImageError),
+      Operation::DownloadSliceImage(static_cast<unsigned int>(index), 
+                                    slice, OrthancStone::SliceImageQuality_FullPam));
   }
 
 
   
   void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice,
                                                    size_t index,
-                                                   SliceImageQuality quality)
+                                                   OrthancStone::SliceImageQuality quality)
   {
     unsigned int value;
     
     switch (quality)
     {
-      case SliceImageQuality_Jpeg50:
+      case OrthancStone::SliceImageQuality_Jpeg50:
         value = 50;
         break;
 
-      case SliceImageQuality_Jpeg90:
+      case OrthancStone::SliceImageQuality_Jpeg90:
         value = 90;
         break;
 
-      case SliceImageQuality_Jpeg95:
+      case OrthancStone::SliceImageQuality_Jpeg95:
         value = 95;
         break;
       
@@ -839,15 +850,20 @@
                        boost::lexical_cast<std::string>(slice.GetFrame()));
 
     orthanc_.GetJsonAsync(uri,
-                          new Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSliceImageJpeg),
-                          new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnSliceImageError),
-                          Operation::DownloadSliceImage(index, slice, quality));
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        OrthancApiClient::JsonResponseReadyMessage>
+          (*this, &OrthancSlicesLoader::ParseSliceImageJpeg),
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        IWebService::HttpRequestErrorMessage>
+          (*this, &OrthancSlicesLoader::OnSliceImageError),
+        Operation::DownloadSliceImage(
+          static_cast<unsigned int>(index), slice, quality));
   }
   
   
   
   void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index,
-                                                   SliceImageQuality quality)
+                                                   OrthancStone::SliceImageQuality quality)
   {
     if (state_ != State_GeometryReady)
     {
@@ -860,10 +876,10 @@
     {
       switch (quality)
       {
-        case SliceImageQuality_FullPng:
+        case OrthancStone::SliceImageQuality_FullPng:
           ScheduleSliceImagePng(slice, index);
           break;
-        case SliceImageQuality_FullPam:
+        case OrthancStone::SliceImageQuality_FullPam:
           ScheduleSliceImagePam(slice, index);
           break;
         default:
@@ -875,9 +891,14 @@
       std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
                          boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz");
       orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(),
-                              new Callable<OrthancSlicesLoader, OrthancApiClient::BinaryResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSliceRawImage),
-                              new Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnSliceImageError),
-                              Operation::DownloadSliceRawImage(index, slice));
+        new OrthancStone::Callable<OrthancSlicesLoader, 
+          OrthancApiClient::BinaryResponseReadyMessage>
+            (*this, &OrthancSlicesLoader::ParseSliceRawImage),
+        new OrthancStone::Callable<OrthancSlicesLoader,
+          IWebService::HttpRequestErrorMessage>
+            (*this, &OrthancSlicesLoader::OnSliceImageError),
+        Operation::DownloadSliceRawImage(
+          static_cast<unsigned int>(index), slice));
     }
   }
 }
--- a/Framework/Toolbox/OrthancSlicesLoader.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.h	Tue May 21 13:25:58 2019 +0200
@@ -31,16 +31,16 @@
 #include <Core/Images/Image.h>
 
 
-namespace OrthancStone
+namespace Deprecated
 {
-  class OrthancSlicesLoader : public IObservable, public IObserver
+  class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryErrorMessage, OrthancSlicesLoader);
 
     
-    class SliceImageReadyMessage : public OriginMessage<OrthancSlicesLoader>
+    class SliceImageReadyMessage : public OrthancStone::OriginMessage<OrthancSlicesLoader>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
@@ -48,14 +48,14 @@
       unsigned int                   sliceIndex_;
       const Slice&                   slice_;
       const Orthanc::ImageAccessor&  image_;
-      SliceImageQuality              effectiveQuality_;
+      OrthancStone::SliceImageQuality  effectiveQuality_;
 
     public:
       SliceImageReadyMessage(const OrthancSlicesLoader& origin,
                              unsigned int sliceIndex,
                              const Slice& slice,
                              const Orthanc::ImageAccessor& image,
-                             SliceImageQuality effectiveQuality) :
+                             OrthancStone::SliceImageQuality effectiveQuality) :
         OriginMessage(origin),
         sliceIndex_(sliceIndex),
         slice_(slice),
@@ -79,27 +79,27 @@
         return image_;
       }
 
-      SliceImageQuality GetEffectiveQuality() const
+      OrthancStone::SliceImageQuality GetEffectiveQuality() const
       {
         return effectiveQuality_;
       }        
     };
     
 
-    class SliceImageErrorMessage : public OriginMessage<OrthancSlicesLoader>
+    class SliceImageErrorMessage : public OrthancStone::OriginMessage<OrthancSlicesLoader>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
       const Slice&       slice_;
       unsigned int       sliceIndex_;
-      SliceImageQuality  effectiveQuality_;
+      OrthancStone::SliceImageQuality  effectiveQuality_;
 
     public:
       SliceImageErrorMessage(const OrthancSlicesLoader& origin,
                              unsigned int sliceIndex,
                              const Slice& slice,
-                             SliceImageQuality effectiveQuality) :
+                             OrthancStone::SliceImageQuality effectiveQuality) :
         OriginMessage(origin),
         slice_(slice),
         sliceIndex_(sliceIndex),
@@ -116,7 +116,7 @@
         return slice_;
       }
 
-      SliceImageQuality GetEffectiveQuality() const
+      OrthancStone::SliceImageQuality GetEffectiveQuality() const
       {
         return effectiveQuality_;
       }        
@@ -145,7 +145,7 @@
 
     OrthancApiClient&  orthanc_;
     State         state_;
-    SlicesSorter  slices_;
+    OrthancStone::SlicesSorter  slices_;
 
     void NotifySliceImageSuccess(const Operation& operation,
                                  const Orthanc::ImageAccessor& image);
@@ -178,12 +178,12 @@
 
     void ScheduleSliceImageJpeg(const Slice& slice,
                                 size_t index,
-                                SliceImageQuality quality);
+                                OrthancStone::SliceImageQuality quality);
 
     void SortAndFinalizeSlices();
     
   public:
-    OrthancSlicesLoader(MessageBroker& broker,
+    OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
                         //ISliceLoaderObserver& callback,
                         OrthancApiClient& orthancApi);
 
@@ -201,9 +201,9 @@
     const Slice& GetSlice(size_t index) const;
 
     bool LookupSlice(size_t& index,
-                     const CoordinateSystem3D& plane) const;
+                     const OrthancStone::CoordinateSystem3D& plane) const;
 
     void ScheduleLoadSliceImage(size_t index,
-                                SliceImageQuality requestedQuality);
+                                OrthancStone::SliceImageQuality requestedQuality);
   };
 }
--- a/Framework/Toolbox/ParallelSlicesCursor.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/ParallelSlicesCursor.cpp	Tue May 21 13:25:58 2019 +0200
@@ -110,7 +110,7 @@
       return false;
     }
 
-    int count = slices_->GetSliceCount();
+    int count = static_cast<int>(slices_->GetSliceCount());
     if (count == 0)
     {
       return false;
@@ -123,7 +123,7 @@
     }
     else
     {
-      slice = currentSlice_;
+      slice = static_cast<int>(currentSlice_);
     }
 
     switch (mode)
--- a/Framework/Toolbox/ShearWarpProjectiveTransform.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/ShearWarpProjectiveTransform.cpp	Tue May 21 13:25:58 2019 +0200
@@ -195,15 +195,20 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
     }
 
-    intermediateWidth_ = std::ceil(extent.GetWidth() / maxScaling);
-    intermediateHeight_ = std::ceil(extent.GetHeight() / maxScaling);
+    intermediateWidth_ = 
+      static_cast<unsigned int>(std::ceil(extent.GetWidth() / maxScaling));
+    intermediateHeight_ = 
+      static_cast<unsigned int>(std::ceil(extent.GetHeight() / maxScaling));
 
     // This is the product "T * S" in Equation (A.16) on page 209
     Matrix TS = LinearAlgebra::Product(
-      GeometryToolbox::CreateTranslationMatrix(static_cast<double>(intermediateWidth_) / 2.0,
-                                               static_cast<double>(intermediateHeight_) / 2.0, 0),
-      GeometryToolbox::CreateScalingMatrix(1.0 / maxScaling, 1.0 / maxScaling, 1),
-      GeometryToolbox::CreateTranslationMatrix(-extent.GetCenterX(), -extent.GetCenterY(), 0));
+      GeometryToolbox::CreateTranslationMatrix(
+        static_cast<double>(intermediateWidth_) / 2.0,
+        static_cast<double>(intermediateHeight_) / 2.0, 0),
+      GeometryToolbox::CreateScalingMatrix(
+        1.0 / maxScaling, 1.0 / maxScaling, 1),
+      GeometryToolbox::CreateTranslationMatrix(
+        -extent.GetCenterX(), -extent.GetCenterY(), 0));
     
     // This is Equation (A.16) on page 209. WARNING: There is an
     // error in Lacroute's thesis: "inv(MM_shear)" is used instead
@@ -380,8 +385,8 @@
     
     // Compute the "world" matrix that maps the source volume to the
     // (0,0,0)->(1,1,1) unit cube
-    Vector origin = source.GetCoordinates(0, 0, 0);
-    Vector ps = source.GetVoxelDimensions(VolumeProjection_Axial);
+    Vector origin = source.GetGeometry().GetCoordinates(0, 0, 0);
+    Vector ps = source.GetGeometry().GetVoxelDimensions(VolumeProjection_Axial);
     Matrix world = LinearAlgebra::Product(
       GeometryToolbox::CreateScalingMatrix(1.0 / ps[0], 1.0 / ps[1], 1.0 / ps[2]),
       GeometryToolbox::CreateTranslationMatrix(-origin[0], -origin[1], -origin[2]));
@@ -538,7 +543,8 @@
         }
         else
         {
-          *p = *qacc / static_cast<float>(*qcount);
+          *p = static_cast<typename TargetTraits::PixelType>
+            (*qacc / static_cast<float>(*qcount));
 
           if (*p > maxValue)
           {
--- a/Framework/Toolbox/Slice.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/Slice.cpp	Tue May 21 13:25:58 2019 +0200
@@ -30,7 +30,7 @@
 
 #include <boost/lexical_cast.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   static bool ParseDouble(double& target,
                           const std::string& source)
@@ -118,16 +118,16 @@
       return false;
     }
 
-    if (!LinearAlgebra::IsCloseToZero(offset0))
+    if (!OrthancStone::LinearAlgebra::IsCloseToZero(offset0))
     {
       LOG(ERROR) << "Invalid syntax";
       return false;
     }
 
-    geometry_ = CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
-                                   //+ 650 * geometry_.GetAxisX(),
-                                   geometry_.GetAxisX(),
-                                   geometry_.GetAxisY());
+    geometry_ = OrthancStone::CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
+                                                 //+ 650 * geometry_.GetAxisX(),
+                                                 geometry_.GetAxisX(),
+                                                 geometry_.GetAxisY());
 
     thickness_ = offset1 - offset0;
     if (thickness_ < 0)
@@ -185,19 +185,19 @@
     
     converter_.ReadParameters(dataset);
 
-    GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
+    OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
 
     std::string position, orientation;
     if (dataset.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) &&
         dataset.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false))
     {
-      geometry_ = CoordinateSystem3D(position, orientation);
+      geometry_ = OrthancStone::CoordinateSystem3D(position, orientation);
 
       bool ok = true;
 
-      switch (StringToSopClassUid(sopClassUid_))
+      switch (OrthancStone::StringToSopClassUid(sopClassUid_))
       {
-        case SopClassUid_RTDose:
+        case OrthancStone::SopClassUid_RTDose:
           type_ = Type_OrthancRawFrame;
           ok = ComputeRTDoseGeometry(dataset, frame);
           break;
@@ -243,7 +243,7 @@
   }
 
   
-  const CoordinateSystem3D& Slice::GetGeometry() const
+  const OrthancStone::CoordinateSystem3D& Slice::GetGeometry() const
   {
     if (type_ == Type_Invalid)
     {
@@ -320,7 +320,7 @@
   }
 
 
-  bool Slice::ContainsPlane(const CoordinateSystem3D& plane) const
+  bool Slice::ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
   {
     if (type_ == Type_Invalid)
     {
@@ -328,16 +328,16 @@
     }
 
     bool opposite;
-    return (GeometryToolbox::IsParallelOrOpposite(opposite,
-                                                  GetGeometry().GetNormal(),
-                                                  plane.GetNormal()) &&
-            LinearAlgebra::IsNear(GetGeometry().ProjectAlongNormal(GetGeometry().GetOrigin()),
-                                  GetGeometry().ProjectAlongNormal(plane.GetOrigin()),
-                                  thickness_ / 2.0));
+    return (OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite,
+                                                                GetGeometry().GetNormal(),
+                                                                plane.GetNormal()) &&
+            OrthancStone::LinearAlgebra::IsNear(GetGeometry().ProjectAlongNormal(GetGeometry().GetOrigin()),
+                                                GetGeometry().ProjectAlongNormal(plane.GetOrigin()),
+                                                thickness_ / 2.0));
   }
 
   
-  void Slice::GetExtent(std::vector<Vector>& points) const
+  void Slice::GetExtent(std::vector<OrthancStone::Vector>& points) const
   {
     double sx = GetPixelSpacingX();
     double sy = GetPixelSpacingY();
--- a/Framework/Toolbox/Slice.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/Slice.h	Tue May 21 13:25:58 2019 +0200
@@ -27,7 +27,7 @@
 #include <Core/DicomFormat/DicomImageInformation.h>
 #include <Core/IDynamicObject.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   // TODO - Remove this class
   class Slice :
@@ -51,7 +51,7 @@
     std::string          sopClassUid_;
     unsigned int         frame_;
     unsigned int         frameCount_;   // TODO : Redundant with "imageInformation_"
-    CoordinateSystem3D   geometry_;
+    OrthancStone::CoordinateSystem3D   geometry_;
     double               pixelSpacingX_;
     double               pixelSpacingY_;
     double               thickness_;
@@ -79,7 +79,7 @@
 
     // TODO Is this constructor the best way to go to tackle missing
     // layers within SliceViewerWidget?
-    Slice(const CoordinateSystem3D& plane,
+    Slice(const OrthancStone::CoordinateSystem3D& plane,
           double thickness) :
       type_(Type_Standalone),
       frame_(0),
@@ -93,7 +93,7 @@
     {      
     }
 
-    Slice(const CoordinateSystem3D& plane,
+    Slice(const OrthancStone::CoordinateSystem3D& plane,
           double pixelSpacingX,
           double pixelSpacingY,
           double thickness,
@@ -130,7 +130,7 @@
 
     unsigned int GetFrame() const;
 
-    const CoordinateSystem3D& GetGeometry() const;
+    const OrthancStone::CoordinateSystem3D& GetGeometry() const;
 
     double GetThickness() const;
 
@@ -144,9 +144,9 @@
 
     const DicomFrameConverter& GetConverter() const;
 
-    bool ContainsPlane(const CoordinateSystem3D& plane) const;
+    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const;
 
-    void GetExtent(std::vector<Vector>& points) const;
+    void GetExtent(std::vector<OrthancStone::Vector>& points) const;
 
     const Orthanc::DicomImageInformation& GetImageInformation() const;
 
--- a/Framework/Toolbox/SlicesSorter.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/SlicesSorter.h	Tue May 21 13:25:58 2019 +0200
@@ -84,7 +84,8 @@
     // slices. This is notably the case if all the slices are not
     // parallel to the reference normal that will be selected.
     bool Sort();
-    
+
+    // TODO - Remove this
     bool LookupClosestSlice(size_t& index,
                             double& distance,
                             const CoordinateSystem3D& slice) const;
--- a/Framework/Toolbox/ViewportGeometry.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/ViewportGeometry.cpp	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 
 #include <boost/math/special_functions/round.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   void ViewportGeometry::ComputeTransform()
   {
@@ -79,7 +79,7 @@
   }
 
 
-  void ViewportGeometry::SetSceneExtent(const Extent2D& extent)
+  void ViewportGeometry::SetSceneExtent(const OrthancStone::Extent2D& extent)
   {
     LOG(INFO) << "New scene extent: ("
               << extent.GetX1() << "," << extent.GetY1() << ") => ("
@@ -128,7 +128,12 @@
     sceneTouches.clear();
     for (size_t t = 0; t < displayTouches.size(); t++)
     {
-      MapPixelCenterToScene(sceneX, sceneY, displayTouches[t].x, displayTouches[t].y);
+      MapPixelCenterToScene(
+        sceneX,
+        sceneY, 
+        static_cast<int>(displayTouches[t].x), 
+        static_cast<int>(displayTouches[t].y));
+      
       sceneTouches.push_back(Touch((float)sceneX, (float)sceneY));
     }
   }
@@ -163,7 +168,7 @@
   }
 
 
-  void ViewportGeometry::ApplyTransform(CairoContext& context) const
+  void ViewportGeometry::ApplyTransform(OrthancStone::CairoContext& context) const
   {
     cairo_set_matrix(context.GetObject(), &transform_);
   }
@@ -193,9 +198,9 @@
   }
 
 
-  Matrix ViewportGeometry::GetMatrix() const
+  OrthancStone::Matrix ViewportGeometry::GetMatrix() const
   {
-    Matrix m(3, 3);
+    OrthancStone::Matrix m(3, 3);
 
     m(0, 0) = transform_.xx;
     m(0, 1) = transform_.xy;
--- a/Framework/Toolbox/ViewportGeometry.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Toolbox/ViewportGeometry.h	Tue May 21 13:25:58 2019 +0200
@@ -26,13 +26,13 @@
 #include "LinearAlgebra.h"
 #include "../Viewport/IMouseTracker.h"  // to include "Touch" definition
 
-namespace OrthancStone
+namespace Deprecated
 {
   class ViewportGeometry
   {
   private:
     // Extent of the scene (in world units)
-    Extent2D   sceneExtent_;
+    OrthancStone::Extent2D   sceneExtent_;
 
     // Size of the display (in pixels)
     unsigned int  width_;
@@ -53,9 +53,9 @@
     void SetDisplaySize(unsigned int width,
                         unsigned int height);
 
-    void SetSceneExtent(const Extent2D& extent);
+    void SetSceneExtent(const OrthancStone::Extent2D& extent);
 
-    const Extent2D& GetSceneExtent() const
+    const OrthancStone::Extent2D& GetSceneExtent() const
     {
       return sceneExtent_;
     }
@@ -95,7 +95,7 @@
 
     void FitContent();
 
-    void ApplyTransform(CairoContext& context) const;
+    void ApplyTransform(OrthancStone::CairoContext& context) const;
 
     void GetPan(double& x,
                 double& y) const;
@@ -105,6 +105,6 @@
 
     void SetZoom(double zoom);
 
-    Matrix GetMatrix() const;
+    OrthancStone::Matrix GetMatrix() const;
   };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Toolbox/VolumeImageGeometry.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,309 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "VolumeImageGeometry.h"
+
+#include "../Toolbox/GeometryToolbox.h"
+
+#include <Core/OrthancException.h>
+
+
+namespace OrthancStone
+{
+  void VolumeImageGeometry::Invalidate()
+  {
+    Vector p = (axialGeometry_.GetOrigin() +
+                static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal());
+        
+    coronalGeometry_ = CoordinateSystem3D(p,
+                                          axialGeometry_.GetAxisX(),
+                                          -axialGeometry_.GetNormal());
+    
+    sagittalGeometry_ = CoordinateSystem3D(p,
+                                           axialGeometry_.GetAxisY(),
+                                           axialGeometry_.GetNormal());
+
+    Vector origin = (
+      axialGeometry_.MapSliceToWorldCoordinates(-0.5 * voxelDimensions_[0],
+                                                -0.5 * voxelDimensions_[1]) -
+      0.5 * voxelDimensions_[2] * axialGeometry_.GetNormal());
+
+    Vector scaling;
+    
+    if (width_ == 0 ||
+        height_ == 0 ||
+        depth_ == 0)
+    {
+      LinearAlgebra::AssignVector(scaling, 1, 1, 1);
+    }
+    else
+    {
+      scaling = (
+        axialGeometry_.GetAxisX() * voxelDimensions_[0] * static_cast<double>(width_) +
+        axialGeometry_.GetAxisY() * voxelDimensions_[1] * static_cast<double>(height_) +
+        axialGeometry_.GetNormal() * voxelDimensions_[2] * static_cast<double>(depth_));
+    }
+
+    transform_ = LinearAlgebra::Product(
+      GeometryToolbox::CreateTranslationMatrix(origin[0], origin[1], origin[2]),
+      GeometryToolbox::CreateScalingMatrix(scaling[0], scaling[1], scaling[2]));
+
+    LinearAlgebra::InvertMatrix(transformInverse_, transform_);
+  }
+
+  
+  VolumeImageGeometry::VolumeImageGeometry() :
+    width_(0),
+    height_(0),
+    depth_(0)
+  {
+    LinearAlgebra::AssignVector(voxelDimensions_, 1, 1, 1);
+    Invalidate();
+  }
+
+
+  void VolumeImageGeometry::SetSize(unsigned int width,
+                                    unsigned int height,
+                                    unsigned int depth)
+  {
+    width_ = width;
+    height_ = height;
+    depth_ = depth;
+    Invalidate();
+  }
+
+  
+  void VolumeImageGeometry::SetAxialGeometry(const CoordinateSystem3D& geometry)
+  {
+    axialGeometry_ = geometry;
+    Invalidate();
+  }
+
+
+  void VolumeImageGeometry::SetVoxelDimensions(double x,
+                                               double y,
+                                               double z)
+  {
+    if (x <= 0 ||
+        y <= 0 ||
+        z <= 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      LinearAlgebra::AssignVector(voxelDimensions_, x, y, z);
+      Invalidate();
+    }
+  }
+
+
+  const CoordinateSystem3D& VolumeImageGeometry::GetProjectionGeometry(VolumeProjection projection) const
+  {
+    switch (projection)
+    {
+      case VolumeProjection_Axial:
+        return axialGeometry_;
+
+      case VolumeProjection_Coronal:
+        return coronalGeometry_;
+
+      case VolumeProjection_Sagittal:
+        return sagittalGeometry_;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+  
+  Vector VolumeImageGeometry::GetVoxelDimensions(VolumeProjection projection) const
+  {
+    switch (projection)
+    {
+      case VolumeProjection_Axial:
+        return voxelDimensions_;
+
+      case VolumeProjection_Coronal:
+        return LinearAlgebra::CreateVector(voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]);
+
+      case VolumeProjection_Sagittal:
+        return LinearAlgebra::CreateVector(voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]);
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  unsigned int VolumeImageGeometry::GetProjectionWidth(VolumeProjection projection) const
+  {
+    switch (projection)
+    {
+      case VolumeProjection_Axial:
+        return width_;
+
+      case VolumeProjection_Coronal:
+        return width_;
+
+      case VolumeProjection_Sagittal:
+        return height_;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  unsigned int VolumeImageGeometry::GetProjectionHeight(VolumeProjection projection) const
+  {
+    switch (projection)
+    {
+      case VolumeProjection_Axial:
+        return height_;
+
+      case VolumeProjection_Coronal:
+        return depth_;
+
+      case VolumeProjection_Sagittal:
+        return depth_;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  unsigned int VolumeImageGeometry::GetProjectionDepth(VolumeProjection projection) const
+  {
+    switch (projection)
+    {
+      case VolumeProjection_Axial:
+        return depth_;
+
+      case VolumeProjection_Coronal:
+        return height_;
+
+      case VolumeProjection_Sagittal:
+        return width_;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }    
+  }
+
+
+  Vector VolumeImageGeometry::GetCoordinates(float x,
+                                             float y,
+                                             float z) const
+  {
+    Vector p = LinearAlgebra::Product(transform_, LinearAlgebra::CreateVector(x, y, z, 1));
+
+    assert(LinearAlgebra::IsNear(p[3], 1));  // Affine transform, no perspective effect
+
+    // Back to non-homogeneous coordinates
+    return LinearAlgebra::CreateVector(p[0], p[1], p[2]);
+  }
+
+
+  bool VolumeImageGeometry::DetectProjection(VolumeProjection& projection,
+                                             const Vector& planeNormal) const
+  {
+    if (GeometryToolbox::IsParallel(planeNormal, axialGeometry_.GetNormal()))
+    {
+      projection = VolumeProjection_Axial;
+      return true;
+    }
+    else if (GeometryToolbox::IsParallel(planeNormal, coronalGeometry_.GetNormal()))
+    {
+      projection = VolumeProjection_Coronal;
+      return true;
+    }
+    else if (GeometryToolbox::IsParallel(planeNormal, sagittalGeometry_.GetNormal()))
+    {
+      projection = VolumeProjection_Sagittal;
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  
+  bool VolumeImageGeometry::DetectSlice(VolumeProjection& projection,
+                                        unsigned int& slice,
+                                        const CoordinateSystem3D& plane) const
+  {
+    if (!DetectProjection(projection, plane.GetNormal()))
+    {
+      return false;
+    }
+
+    // Transforms the coordinates of the origin of the plane, into the
+    // coordinates of the axial geometry
+    const Vector& origin = plane.GetOrigin();
+    Vector p = LinearAlgebra::Product(
+      transformInverse_,
+      LinearAlgebra::CreateVector(origin[0], origin[1], origin[2], 1));
+
+    assert(LinearAlgebra::IsNear(p[3], 1));
+
+    double z;
+
+    switch (projection)
+    {
+      case VolumeProjection_Axial:
+        z = p[2];
+        break;
+
+      case VolumeProjection_Coronal:
+        z = p[1];
+        break;
+
+      case VolumeProjection_Sagittal:
+        z = p[0];
+        break;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    const unsigned int projectionDepth = GetProjectionDepth(projection);
+    
+    z *= static_cast<double>(projectionDepth);
+    if (z < 0)
+    {
+      return false;
+    }
+        
+    unsigned int d = static_cast<unsigned int>(std::floor(z));
+    if (d >= projectionDepth)
+    {
+      return false;
+    }
+    else
+    {
+      slice = d;
+      return true;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Toolbox/VolumeImageGeometry.h	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,122 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../StoneEnumerations.h"
+#include "CoordinateSystem3D.h"
+
+namespace OrthancStone
+{
+  class VolumeImageGeometry
+  {
+  private:
+    unsigned int           width_;
+    unsigned int           height_;
+    unsigned int           depth_;
+    CoordinateSystem3D     axialGeometry_;
+    CoordinateSystem3D     coronalGeometry_;
+    CoordinateSystem3D     sagittalGeometry_;
+    Vector                 voxelDimensions_;
+    Matrix                 transform_;
+    Matrix                 transformInverse_;
+
+    void Invalidate();
+
+  public:
+    VolumeImageGeometry();
+
+    unsigned int GetWidth() const
+    {
+      return width_;
+    }
+
+    unsigned int GetHeight() const
+    {
+      return height_;
+    }
+
+    unsigned int GetDepth() const
+    {
+      return depth_;
+    }
+
+    const CoordinateSystem3D& GetAxialGeometry() const
+    {
+      return axialGeometry_;
+    }
+
+    const CoordinateSystem3D& GetCoronalGeometry() const
+    {
+      return coronalGeometry_;
+    }
+
+    const CoordinateSystem3D& GetSagittalGeometry() const
+    {
+      return sagittalGeometry_;
+    }
+
+    const CoordinateSystem3D& GetProjectionGeometry(VolumeProjection projection) const;
+    
+    const Matrix& GetTransform() const
+    {
+      return transform_;
+    }
+
+    const Matrix& GetTransformInverse() const
+    {
+      return transformInverse_;
+    }
+
+    void SetSize(unsigned int width,
+                 unsigned int height,
+                 unsigned int depth);
+
+    // Set the geometry of the first axial slice (i.e. the one whose
+    // depth == 0)
+    void SetAxialGeometry(const CoordinateSystem3D& geometry);
+
+    void SetVoxelDimensions(double x,
+                            double y,
+                            double z);
+
+    Vector GetVoxelDimensions(VolumeProjection projection) const;
+
+    unsigned int GetProjectionWidth(VolumeProjection projection) const;
+
+    unsigned int GetProjectionHeight(VolumeProjection projection) const;
+
+    unsigned int GetProjectionDepth(VolumeProjection projection) const;
+
+    // Get the 3D position of a point in the volume, where x, y and z
+    // lie in the [0;1] range
+    Vector GetCoordinates(float x,
+                          float y,
+                          float z) const;
+
+    bool DetectProjection(VolumeProjection& projection,
+                          const Vector& planeNormal) const;
+
+    bool DetectSlice(VolumeProjection& projection,
+                     unsigned int& slice,
+                     const CoordinateSystem3D& plane) const;
+  };
+}
--- a/Framework/Viewport/IMouseTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Viewport/IMouseTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include "CairoSurface.h"
 #include <vector>
 
-namespace OrthancStone
+namespace Deprecated
 {
   struct Touch
   {
--- a/Framework/Viewport/IStatusBar.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Viewport/IStatusBar.h	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <string>
 #include <boost/noncopyable.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class IStatusBar : public boost::noncopyable
   {
--- a/Framework/Viewport/IViewport.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Viewport/IViewport.h	Tue May 21 13:25:58 2019 +0200
@@ -28,16 +28,16 @@
 #include <Core/Images/ImageAccessor.h>
 #include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition
 
-namespace OrthancStone
+namespace Deprecated
 {
   class IWidget;   // Forward declaration
   
-  class IViewport : public IObservable
+  class IViewport : public OrthancStone::IObservable
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport);
 
-    IViewport(MessageBroker& broker) :
+    IViewport(OrthancStone::MessageBroker& broker) :
       IObservable(broker)
     {
     }
@@ -56,10 +56,10 @@
     // The function returns "true" iff. a new frame was rendered
     virtual bool Render(Orthanc::ImageAccessor& surface) = 0;
 
-    virtual void MouseDown(MouseButton button,
+    virtual void MouseDown(OrthancStone::MouseButton button,
                            int x,
                            int y,
-                           KeyboardModifiers modifiers,
+                           OrthancStone::KeyboardModifiers modifiers,
                            const std::vector<Touch>& touches) = 0;
 
     virtual void MouseUp() = 0;
@@ -72,14 +72,14 @@
 
     virtual void MouseLeave() = 0;
 
-    virtual void MouseWheel(MouseWheelDirection direction,
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                             int x,
                             int y,
-                            KeyboardModifiers modifiers) = 0;
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
 
-    virtual void KeyPressed(KeyboardKeys key,
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers) = 0;
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
 
     virtual bool HasAnimation() = 0;
 
--- a/Framework/Viewport/WidgetViewport.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Viewport/WidgetViewport.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,9 +24,9 @@
 #include <Core/Images/ImageProcessing.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  WidgetViewport::WidgetViewport(MessageBroker& broker) :
+  WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) :
     IViewport(broker),
     statusBar_(NULL),
     isMouseOver_(false),
@@ -139,7 +139,7 @@
 
   void WidgetViewport::TouchStart(const std::vector<Touch>& displayTouches)
   {
-    MouseDown(MouseButton_Left, (int)displayTouches[0].x, (int)displayTouches[0].y, KeyboardModifiers_None, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates
+    MouseDown(OrthancStone::MouseButton_Left, (int)displayTouches[0].x, (int)displayTouches[0].y, OrthancStone::KeyboardModifiers_None, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates
   }
       
   void WidgetViewport::TouchMove(const std::vector<Touch>& displayTouches)
@@ -154,10 +154,10 @@
     MouseUp();
   }
 
-  void WidgetViewport::MouseDown(MouseButton button,
+  void WidgetViewport::MouseDown(OrthancStone::MouseButton button,
                                  int x,
                                  int y,
-                                 KeyboardModifiers modifiers,
+                                 OrthancStone::KeyboardModifiers modifiers,
                                  const std::vector<Touch>& displayTouches
                                  )
   {
@@ -241,10 +241,10 @@
   }
 
 
-  void WidgetViewport::MouseWheel(MouseWheelDirection direction,
+  void WidgetViewport::MouseWheel(OrthancStone::MouseWheelDirection direction,
                                   int x,
                                   int y,
-                                  KeyboardModifiers modifiers)
+                                  OrthancStone::KeyboardModifiers modifiers)
   {
     if (centralWidget_.get() != NULL &&
         mouseTracker_.get() == NULL)
@@ -254,9 +254,9 @@
   }
 
 
-  void WidgetViewport::KeyPressed(KeyboardKeys key,
+  void WidgetViewport::KeyPressed(OrthancStone::KeyboardKeys key,
                                   char keyChar,
-                                  KeyboardModifiers modifiers)
+                                  OrthancStone::KeyboardModifiers modifiers)
   {
     if (centralWidget_.get() != NULL &&
         mouseTracker_.get() == NULL)
--- a/Framework/Viewport/WidgetViewport.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Viewport/WidgetViewport.h	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 
 #include <memory>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WidgetViewport : public IViewport
   {
@@ -37,11 +37,11 @@
     bool                          isMouseOver_;
     int                           lastMouseX_;
     int                           lastMouseY_;
-    CairoSurface                  background_;
+    OrthancStone::CairoSurface    background_;
     bool                          backgroundChanged_;
 
   public:
-    WidgetViewport(MessageBroker& broker);
+    WidgetViewport(OrthancStone::MessageBroker& broker);
 
     virtual void FitContent();
 
@@ -56,10 +56,10 @@
 
     virtual bool Render(Orthanc::ImageAccessor& surface);
 
-    virtual void MouseDown(MouseButton button,
+    virtual void MouseDown(OrthancStone::MouseButton button,
                            int x,
                            int y,
-                           KeyboardModifiers modifiers,
+                           OrthancStone::KeyboardModifiers modifiers,
                            const std::vector<Touch>& displayTouches);
 
     virtual void MouseUp();
@@ -78,14 +78,14 @@
     
     virtual void TouchEnd(const std::vector<Touch>& touches);
 
-    virtual void MouseWheel(MouseWheelDirection direction,
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                             int x,
                             int y,
-                            KeyboardModifiers modifiers);
+                            OrthancStone::KeyboardModifiers modifiers);
 
-    virtual void KeyPressed(KeyboardKeys key,
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers);
+                            OrthancStone::KeyboardModifiers modifiers);
 
     virtual bool HasAnimation();
 
--- a/Framework/Volumes/ISlicedVolume.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/ISlicedVolume.h	Tue May 21 13:25:58 2019 +0200
@@ -24,9 +24,9 @@
 #include "../Messages/IObservable.h"
 #include "../Toolbox/Slice.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
-  class ISlicedVolume : public IObservable
+  class ISlicedVolume : public OrthancStone::IObservable
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, ISlicedVolume);
@@ -35,7 +35,7 @@
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeReadyMessage, ISlicedVolume);
 
 
-    class SliceContentChangedMessage : public OriginMessage<ISlicedVolume>
+    class SliceContentChangedMessage : public OrthancStone::OriginMessage<ISlicedVolume>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
@@ -65,7 +65,7 @@
     };
 
 
-    ISlicedVolume(MessageBroker& broker) :
+    ISlicedVolume(OrthancStone::MessageBroker& broker) :
       IObservable(broker)
     {
     }
--- a/Framework/Volumes/IVolumeLoader.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/IVolumeLoader.h	Tue May 21 13:25:58 2019 +0200
@@ -23,16 +23,16 @@
 
 #include "../Messages/IObservable.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
-  class IVolumeLoader : public IObservable
+  class IVolumeLoader : public OrthancStone::IObservable
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader);
 
-    IVolumeLoader(MessageBroker& broker) :
+    IVolumeLoader(OrthancStone::MessageBroker& broker) :
       IObservable(broker)
     {
     }
--- a/Framework/Volumes/ImageBuffer3D.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/ImageBuffer3D.cpp	Tue May 21 13:25:58 2019 +0200
@@ -21,6 +21,8 @@
 
 #include "ImageBuffer3D.h"
 
+#include "../Toolbox/GeometryToolbox.h"
+
 #include <Core/Images/ImageProcessing.h>
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
@@ -116,7 +118,7 @@
     computeRange_(computeRange),
     hasRange_(false)
   {
-    LinearAlgebra::AssignVector(voxelDimensions_, 1, 1, 1);
+    geometry_.SetSize(width, height, depth);
 
     LOG(INFO) << "Created a 3D image of size " << width << "x" << height
               << "x" << depth << " in " << Orthanc::EnumerationToString(format)
@@ -130,127 +132,57 @@
   }
 
 
-  void ImageBuffer3D::SetAxialGeometry(const CoordinateSystem3D& geometry)
-  {
-    axialGeometry_ = geometry;
-  }
-
-
-  void ImageBuffer3D::SetVoxelDimensions(double x,
-                                         double y,
-                                         double z)
-  {
-    if (x <= 0 ||
-        y <= 0 ||
-        z <= 0)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    {
-      LinearAlgebra::AssignVector(voxelDimensions_, x, y, z);
-    }
-  }
-
-
-  Vector ImageBuffer3D::GetVoxelDimensions(VolumeProjection projection) const
-  {
-    Vector result;
-    switch (projection)
-    {
-    case VolumeProjection_Axial:
-      result = voxelDimensions_;
-      break;
-
-    case VolumeProjection_Coronal:
-      LinearAlgebra::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]);
-      break;
-
-    case VolumeProjection_Sagittal:
-      LinearAlgebra::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]);
-      break;
-
-    default:
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    return result;
-  }
-
-
-  void ImageBuffer3D::GetSliceSize(unsigned int& width,
-                                   unsigned int& height,
-                                   VolumeProjection projection)
-  {
-    switch (projection)
-    {
-    case VolumeProjection_Axial:
-      width = width_;
-      height = height_;
-      break;
-
-    case VolumeProjection_Coronal:
-      width = width_;
-      height = depth_;
-      break;
-
-    case VolumeProjection_Sagittal:
-      width = height_;
-      height = depth_;
-      break;
-
-    default:
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-  }
 
 
   ParallelSlices* ImageBuffer3D::GetGeometry(VolumeProjection projection) const
   {
+    const Vector dimensions = geometry_.GetVoxelDimensions(VolumeProjection_Axial);
+    const CoordinateSystem3D& axial = geometry_.GetAxialGeometry();
+    
     std::auto_ptr<ParallelSlices> result(new ParallelSlices);
 
     switch (projection)
     {
-    case VolumeProjection_Axial:
-      for (unsigned int z = 0; z < depth_; z++)
-      {
-        Vector origin = axialGeometry_.GetOrigin();
-        origin += static_cast<double>(z) * voxelDimensions_[2] * axialGeometry_.GetNormal();
+      case VolumeProjection_Axial:
+        for (unsigned int z = 0; z < depth_; z++)
+        {
+          Vector origin = axial.GetOrigin();
+          origin += static_cast<double>(z) * dimensions[2] * axial.GetNormal();
 
-        result->AddSlice(origin,
-                         axialGeometry_.GetAxisX(),
-                         axialGeometry_.GetAxisY());
-      }
-      break;
+          result->AddSlice(origin,
+                           axial.GetAxisX(),
+                           axial.GetAxisY());
+        }
+        break;
 
-    case VolumeProjection_Coronal:
-      for (unsigned int y = 0; y < height_; y++)
-      {
-        Vector origin = axialGeometry_.GetOrigin();
-        origin += static_cast<double>(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY();
-        origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal();
+      case VolumeProjection_Coronal:
+        for (unsigned int y = 0; y < height_; y++)
+        {
+          Vector origin = axial.GetOrigin();
+          origin += static_cast<double>(y) * dimensions[1] * axial.GetAxisY();
+          origin += static_cast<double>(depth_ - 1) * dimensions[2] * axial.GetNormal();
 
-        result->AddSlice(origin,
-                         axialGeometry_.GetAxisX(),
-                         -axialGeometry_.GetNormal());
-      }
-      break;
+          result->AddSlice(origin,
+                           axial.GetAxisX(),
+                           -axial.GetNormal());
+        }
+        break;
 
-    case VolumeProjection_Sagittal:
-      for (unsigned int x = 0; x < width_; x++)
-      {
-        Vector origin = axialGeometry_.GetOrigin();
-        origin += static_cast<double>(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX();
-        origin += static_cast<double>(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal();
+      case VolumeProjection_Sagittal:
+        for (unsigned int x = 0; x < width_; x++)
+        {
+          Vector origin = axial.GetOrigin();
+          origin += static_cast<double>(x) * dimensions[0] * axial.GetAxisX();
+          origin += static_cast<double>(depth_ - 1) * dimensions[2] * axial.GetNormal();
 
-        result->AddSlice(origin,
-                         axialGeometry_.GetAxisY(),
-                         -axialGeometry_.GetNormal());
-      }
-      break;
+          result->AddSlice(origin,
+                           axial.GetAxisY(),
+                           -axial.GetNormal());
+        }
+        break;
 
-    default:
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
     return result.release();
@@ -276,24 +208,24 @@
 
     switch (slice.GetFormat())
     {
-    case Orthanc::PixelFormat_Grayscale8:
-    case Orthanc::PixelFormat_Grayscale16:
-    case Orthanc::PixelFormat_Grayscale32:
-    case Orthanc::PixelFormat_SignedGrayscale16:
-    {
-      int64_t a, b;
-      Orthanc::ImageProcessing::GetMinMaxIntegerValue(a, b, slice);
-      sliceMin = static_cast<float>(a);
-      sliceMax = static_cast<float>(b);
-      break;
-    }
+      case Orthanc::PixelFormat_Grayscale8:
+      case Orthanc::PixelFormat_Grayscale16:
+      case Orthanc::PixelFormat_Grayscale32:
+      case Orthanc::PixelFormat_SignedGrayscale16:
+      {
+        int64_t a, b;
+        Orthanc::ImageProcessing::GetMinMaxIntegerValue(a, b, slice);
+        sliceMin = static_cast<float>(a);
+        sliceMax = static_cast<float>(b);
+        break;
+      }
 
-    case Orthanc::PixelFormat_Float32:
-      Orthanc::ImageProcessing::GetMinMaxFloatValue(sliceMin, sliceMax, slice);
-      break;
+      case Orthanc::PixelFormat_Float32:
+        Orthanc::ImageProcessing::GetMinMaxFloatValue(sliceMin, sliceMax, slice);
+        break;
 
-    default:
-      return;
+      default:
+        return;
     }
 
     if (hasRange_)
@@ -326,14 +258,21 @@
   }
 
 
-  bool ImageBuffer3D::FitWindowingToRange(RenderStyle& style,
-                                          const DicomFrameConverter& converter) const
+  bool ImageBuffer3D::FitWindowingToRange(Deprecated::RenderStyle& style,
+                                          const Deprecated::DicomFrameConverter& converter) const
   {
     if (hasRange_)
     {
       style.windowing_ = ImageWindowing_Custom;
-      style.customWindowCenter_ = converter.Apply((minValue_ + maxValue_) / 2.0);
-      style.customWindowWidth_ = converter.Apply(maxValue_ - minValue_);
+      
+      // casting the narrower type to wider before calling the + operator
+      // will prevent overflowing (this is why the cast to double is only 
+      // done on the first operand)
+      style.customWindowCenter_ = static_cast<float>(
+        converter.Apply((static_cast<double>(minValue_) + maxValue_) / 2.0));
+      
+      style.customWindowWidth_ = static_cast<float>(
+        converter.Apply(static_cast<double>(maxValue_) - minValue_));
       
       if (style.customWindowWidth_ > 1)
       {
@@ -367,8 +306,8 @@
         sagittal_->GetReadOnlyAccessor(accessor_);
         break;
 
-    default:
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -411,8 +350,8 @@
         sagittal_->GetWriteableAccessor(accessor_);
         break;
 
-    default:
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -457,22 +396,4 @@
     const void* p = image_.GetConstRow(y + height_ * (depth_ - 1 - z));
     return reinterpret_cast<const uint16_t*>(p) [x];
   }
-
-
-  Vector ImageBuffer3D::GetCoordinates(float x,
-                                       float y,
-                                       float z) const
-  {
-    Vector ps = GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
-
-    const CoordinateSystem3D& axial = GetAxialGeometry();
-    
-    Vector origin = (axial.MapSliceToWorldCoordinates(-0.5 * ps[0], -0.5 * ps[1]) -
-        0.5 * ps[2] * axial.GetNormal());
-
-    return (origin +
-            axial.GetAxisX() * ps[0] * x * static_cast<double>(GetWidth()) +
-        axial.GetAxisY() * ps[1] * y * static_cast<double>(GetHeight()) +
-        axial.GetNormal() * ps[2] * z * static_cast<double>(GetDepth()));
-  }
 }
--- a/Framework/Volumes/ImageBuffer3D.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/ImageBuffer3D.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "../StoneEnumerations.h"
 #include "../Layers/RenderStyle.h"
-#include "../Toolbox/CoordinateSystem3D.h"
+#include "../Toolbox/VolumeImageGeometry.h"
 #include "../Toolbox/DicomFrameConverter.h"
 #include "../Toolbox/ParallelSlices.h"
 
@@ -34,8 +34,7 @@
   class ImageBuffer3D : public boost::noncopyable
   {
   private:
-    CoordinateSystem3D     axialGeometry_;
-    Vector                 voxelDimensions_;
+    VolumeImageGeometry    geometry_;  // TODO => Move this out of this class
     Orthanc::Image         image_;
     Orthanc::PixelFormat   format_;
     unsigned int           width_;
@@ -45,6 +44,8 @@
     bool                   hasRange_;
     float                  minValue_;
     float                  maxValue_;
+    Matrix                 transform_;
+    Matrix                 transformInverse_;
 
     void ExtendImageRange(const Orthanc::ImageAccessor& slice);
 
@@ -77,24 +78,15 @@
 
     void Clear();
 
-    // Set the geometry of the first axial slice (i.e. the one whose
-    // depth == 0)
-    void SetAxialGeometry(const CoordinateSystem3D& geometry);
-
-    const CoordinateSystem3D& GetAxialGeometry() const
+    VolumeImageGeometry& GetGeometry()
     {
-      return axialGeometry_;
+      return geometry_;
     }
 
-    void SetVoxelDimensions(double x,
-                            double y,
-                            double z);
-
-    Vector GetVoxelDimensions(VolumeProjection projection) const;
-
-    void GetSliceSize(unsigned int& width,
-                      unsigned int& height,
-                      VolumeProjection projection);
+    const VolumeImageGeometry& GetGeometry() const
+    {
+      return geometry_;
+    }
 
     const Orthanc::ImageAccessor& GetInternalImage() const
     {
@@ -121,6 +113,7 @@
       return format_;
     }
 
+    // TODO - Remove
     ParallelSlices* GetGeometry(VolumeProjection projection) const;
     
     uint64_t GetEstimatedMemorySize() const;
@@ -128,8 +121,8 @@
     bool GetRange(float& minValue,
                   float& maxValue) const;
 
-    bool FitWindowingToRange(RenderStyle& style,
-                             const DicomFrameConverter& converter) const;
+    bool FitWindowingToRange(Deprecated::RenderStyle& style,
+                             const Deprecated::DicomFrameConverter& converter) const;
 
     uint8_t GetVoxelGrayscale8Unchecked(unsigned int x,
                                         unsigned int y,
@@ -160,13 +153,7 @@
                                  unsigned int y,
                                  unsigned int z) const;
 
-    // Get the 3D position of a point in the volume, where x, y and z
-    // lie in the [0;1] range
-    Vector GetCoordinates(float x,
-                          float y,
-                          float z) const;
-
-
+    
     class SliceReader : public boost::noncopyable
     {
     private:
--- a/Framework/Volumes/StructureSetLoader.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/StructureSetLoader.cpp	Tue May 21 13:25:58 2019 +0200
@@ -25,9 +25,9 @@
 
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  StructureSetLoader::StructureSetLoader(MessageBroker& broker,
+  StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker,
                                          OrthancApiClient& orthanc) :
     IVolumeLoader(broker),
     IObserver(broker),
@@ -41,7 +41,7 @@
     OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
 
     Orthanc::DicomMap slice;
-    MessagingToolbox::ConvertDataset(slice, dataset);
+    OrthancStone::MessagingToolbox::ConvertDataset(slice, dataset);
     structureSet_->AddReferencedSlice(slice);
 
     BroadcastMessage(ContentChangedMessage(*this));
@@ -51,7 +51,7 @@
   void StructureSetLoader::OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
     OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
-    structureSet_.reset(new DicomStructureSet(dataset));
+    structureSet_.reset(new OrthancStone::DicomStructureSet(dataset));
 
     std::set<std::string> instances;
     structureSet_->GetReferencedInstances(instances);
@@ -60,7 +60,7 @@
          it != instances.end(); ++it)
     {
       orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it,
-                            new Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted));
+                                         new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted));
     }
 
     BroadcastMessage(GeometryReadyMessage(*this));
@@ -84,7 +84,7 @@
 
     const std::string& instance = lookup[0]["ID"].asString();
     orthanc_.GetJsonAsync("/instances/" + instance + "/tags",
-                          new Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnReferencedSliceLoaded));
+                          new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnReferencedSliceLoaded));
   }
 
   
@@ -97,12 +97,12 @@
     else
     {
       orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050",
-                            new Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnStructureSetLoaded));
+                            new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnStructureSetLoaded));
     }
   }
 
 
-  DicomStructureSet& StructureSetLoader::GetStructureSet()
+  OrthancStone::DicomStructureSet& StructureSetLoader::GetStructureSet()
   {
     if (structureSet_.get() == NULL)
     {
--- a/Framework/Volumes/StructureSetLoader.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/StructureSetLoader.h	Tue May 21 13:25:58 2019 +0200
@@ -25,15 +25,15 @@
 #include "../Toolbox/OrthancApiClient.h"
 #include "IVolumeLoader.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class StructureSetLoader :
     public IVolumeLoader,
-    public IObserver
+    public OrthancStone::IObserver
   {
   private:
     OrthancApiClient&                 orthanc_;
-    std::auto_ptr<DicomStructureSet>  structureSet_;
+    std::auto_ptr<OrthancStone::DicomStructureSet>  structureSet_;
 
     void OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message);
 
@@ -42,7 +42,7 @@
     void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message);
 
   public:
-    StructureSetLoader(MessageBroker& broker,
+    StructureSetLoader(OrthancStone::MessageBroker& broker,
                        OrthancApiClient& orthanc);
 
     void ScheduleLoadInstance(const std::string& instance);
@@ -52,6 +52,6 @@
       return structureSet_.get() != NULL;
     }
 
-    DicomStructureSet& GetStructureSet();
+    OrthancStone::DicomStructureSet& GetStructureSet();
   };
 }
--- a/Framework/Volumes/VolumeReslicer.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Volumes/VolumeReslicer.cpp	Tue May 21 13:25:58 2019 +0200
@@ -749,7 +749,8 @@
   {
     // Choose the default voxel size as the finest voxel dimension
     // of the source volumetric image
-    const OrthancStone::Vector dim = source.GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
+    const OrthancStone::Vector dim =
+      source.GetGeometry().GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
     double voxelSize = dim[0];
     
     if (dim[1] < voxelSize)
--- a/Framework/Widgets/CairoWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/CairoWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <Core/Images/ImageProcessing.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   static bool IsAligned(const Orthanc::ImageAccessor& target)
   {
@@ -51,14 +51,14 @@
 
     if (IsAligned(target))
     {
-      CairoSurface surface(target, false /* no alpha */);
-      CairoContext context(surface);
+      OrthancStone::CairoSurface surface(target, false /* no alpha */);
+      OrthancStone::CairoContext context(surface);
       ClearBackgroundCairo(context);
       return RenderCairo(context);
     }
     else
     {
-      CairoContext context(surface_);
+      OrthancStone::CairoContext context(surface_);
       ClearBackgroundCairo(context);
 
       if (RenderCairo(context))
@@ -82,8 +82,8 @@
   {
     if (IsAligned(target))
     {
-      CairoSurface surface(target, false /* no alpha */);
-      CairoContext context(surface);
+      OrthancStone::CairoSurface surface(target, false /* no alpha */);
+      OrthancStone::CairoContext context(surface);
       RenderMouseOverCairo(context, x, y);
     }
     else
@@ -92,7 +92,7 @@
       surface_.GetWriteableAccessor(accessor);
       Orthanc::ImageProcessing::Copy(accessor, target);
 
-      CairoContext context(surface_);
+      OrthancStone::CairoContext context(surface_);
       RenderMouseOverCairo(context, x, y);
 
       Orthanc::ImageProcessing::Copy(target, accessor);
--- a/Framework/Widgets/CairoWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/CairoWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -23,17 +23,17 @@
 
 #include "WidgetBase.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class CairoWidget : public WidgetBase
   {
   private:
-    CairoSurface   surface_;
+    OrthancStone::CairoSurface   surface_;
 
   protected:
-    virtual bool RenderCairo(CairoContext& context) = 0;
+    virtual bool RenderCairo(OrthancStone::CairoContext& context) = 0;
     
-    virtual void RenderMouseOverCairo(CairoContext& context,
+    virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
                                       int x,
                                       int y) = 0;
     
--- a/Framework/Widgets/EmptyWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/EmptyWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <Core/Images/ImageProcessing.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   bool EmptyWidget::Render(Orthanc::ImageAccessor& surface)
   {
--- a/Framework/Widgets/EmptyWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/EmptyWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "IWidget.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   /**
    * This is a test widget that simply fills its surface with an
@@ -73,10 +73,10 @@
 
     virtual bool Render(Orthanc::ImageAccessor& surface);
 
-    virtual IMouseTracker* CreateMouseTracker(MouseButton button,
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
                                               int x,
                                               int y,
-                                              KeyboardModifiers modifiers,
+                                              OrthancStone::KeyboardModifiers modifiers,
                                               const std::vector<Touch>& touches)
     {
       return NULL;
@@ -88,16 +88,16 @@
     {
     }
 
-    virtual void MouseWheel(MouseWheelDirection direction,
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                             int x,
                             int y,
-                            KeyboardModifiers modifiers)
+                            OrthancStone::KeyboardModifiers modifiers)
     {
     }
 
-    virtual void KeyPressed(KeyboardKeys key,
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers)
+                            OrthancStone::KeyboardModifiers modifiers)
     {
     }
 
--- a/Framework/Widgets/IWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/IWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 #include "../Viewport/IMouseTracker.h"
 #include "../Viewport/IStatusBar.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WidgetViewport;  // Forward declaration
   
@@ -49,10 +49,10 @@
  
     virtual bool Render(Orthanc::ImageAccessor& surface) = 0;
 
-    virtual IMouseTracker* CreateMouseTracker(MouseButton button,
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
                                               int x,
                                               int y,
-                                              KeyboardModifiers modifiers,
+                                              OrthancStone::KeyboardModifiers modifiers,
                                               const std::vector<Touch>& touches) = 0;
 
     virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
@@ -61,14 +61,14 @@
 
     virtual bool HasRenderMouseOver() = 0;
 
-    virtual void MouseWheel(MouseWheelDirection direction,
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                             int x,
                             int y,
-                            KeyboardModifiers modifiers) = 0;
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
 
-    virtual void KeyPressed(KeyboardKeys key,
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers) = 0;
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
 
     virtual bool HasAnimation() const = 0;
 
--- a/Framework/Widgets/IWorldSceneInteractor.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/IWorldSceneInteractor.h	Tue May 21 13:25:58 2019 +0200
@@ -27,7 +27,7 @@
 #include "../StoneEnumerations.h"
 #include "../Viewport/IStatusBar.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
     class WorldSceneWidget;
 
@@ -40,8 +40,8 @@
 
         virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                             const ViewportGeometry& view,
-                                                            MouseButton button,
-                                                            KeyboardModifiers modifiers,
+                                                            OrthancStone::MouseButton button,
+                                                            OrthancStone::KeyboardModifiers modifiers,
                                                             int viewportX,
                                                             int viewportY,
                                                             double x,
@@ -49,7 +49,7 @@
                                                             IStatusBar* statusBar,
                                                             const std::vector<Touch>& touches) = 0;
 
-        virtual void MouseOver(CairoContext& context,
+        virtual void MouseOver(OrthancStone::CairoContext& context,
                                WorldSceneWidget& widget,
                                const ViewportGeometry& view,
                                double x,
@@ -57,14 +57,14 @@
                                IStatusBar* statusBar) = 0;
 
         virtual void MouseWheel(WorldSceneWidget& widget,
-                                MouseWheelDirection direction,
-                                KeyboardModifiers modifiers,
+                                OrthancStone::MouseWheelDirection direction,
+                                OrthancStone::KeyboardModifiers modifiers,
                                 IStatusBar* statusBar) = 0;
 
         virtual void KeyPressed(WorldSceneWidget& widget,
-                                KeyboardKeys key,
+                                OrthancStone::KeyboardKeys key,
                                 char keyChar,
-                                KeyboardModifiers modifiers,
+                                OrthancStone::KeyboardModifiers modifiers,
                                 IStatusBar* statusBar) = 0;
     };
 }
--- a/Framework/Widgets/IWorldSceneMouseTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/IWorldSceneMouseTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include "../Viewport/CairoContext.h"
 #include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition
 
-namespace OrthancStone
+namespace Deprecated
 {
 
   // this is tracking a mouse in scene coordinates/mm unlike
@@ -39,7 +39,7 @@
 
     virtual bool HasRender() const = 0;
 
-    virtual void Render(CairoContext& context,
+    virtual void Render(OrthancStone::CairoContext& context,
                         double zoom) = 0;
 
     virtual void MouseUp() = 0;
--- a/Framework/Widgets/LayoutWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/LayoutWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 
 #include <boost/math/special_functions/round.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class LayoutWidget::LayoutMouseTracker : public IMouseTracker
   {
@@ -154,10 +154,10 @@
       }
     }
 
-    IMouseTracker* CreateMouseTracker(MouseButton button,
+    IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
                                       int x,
                                       int y,
-                                      KeyboardModifiers modifiers,
+                                      OrthancStone::KeyboardModifiers modifiers,
                                       const std::vector<Touch>& touches)
     {
       if (Contains(x, y))
@@ -189,10 +189,10 @@
       }
     }
 
-    void MouseWheel(MouseWheelDirection direction,
+    void MouseWheel(OrthancStone::MouseWheelDirection direction,
                     int x,
                     int y,
-                    KeyboardModifiers modifiers)
+                    OrthancStone::KeyboardModifiers modifiers)
     {
       if (Contains(x, y))
       {
@@ -419,10 +419,10 @@
   }
 
     
-  IMouseTracker* LayoutWidget::CreateMouseTracker(MouseButton button,
+  IMouseTracker* LayoutWidget::CreateMouseTracker(OrthancStone::MouseButton button,
                                                   int x,
                                                   int y,
-                                                  KeyboardModifiers modifiers,
+                                                  OrthancStone::KeyboardModifiers modifiers,
                                                   const std::vector<Touch>& touches)
   {
     for (size_t i = 0; i < children_.size(); i++)
@@ -449,10 +449,10 @@
   }
 
 
-  void LayoutWidget::MouseWheel(MouseWheelDirection direction,
+  void LayoutWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
                                 int x,
                                 int y,
-                                KeyboardModifiers modifiers)
+                                OrthancStone::KeyboardModifiers modifiers)
   {
     for (size_t i = 0; i < children_.size(); i++)
     {
@@ -461,9 +461,9 @@
   }
 
 
-  void LayoutWidget::KeyPressed(KeyboardKeys key,
+  void LayoutWidget::KeyPressed(OrthancStone::KeyboardKeys key,
                                 char keyChar,
-                                KeyboardModifiers modifiers)
+                                OrthancStone::KeyboardModifiers modifiers)
   {
     for (size_t i = 0; i < children_.size(); i++)
     {
--- a/Framework/Widgets/LayoutWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/LayoutWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 #include <vector>
 #include <memory>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class LayoutWidget : public WidgetBase
   {
@@ -103,24 +103,24 @@
 
     virtual bool Render(Orthanc::ImageAccessor& surface);
     
-    virtual IMouseTracker* CreateMouseTracker(MouseButton button,
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
                                               int x,
                                               int y,
-                                              KeyboardModifiers modifiers,
+                                              OrthancStone::KeyboardModifiers modifiers,
                                               const std::vector<Touch>& touches);
 
     virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
                                  int x,
                                  int y);
 
-    virtual void MouseWheel(MouseWheelDirection direction,
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                             int x,
                             int y,
-                            KeyboardModifiers modifiers);
+                            OrthancStone::KeyboardModifiers modifiers);
 
-    virtual void KeyPressed(KeyboardKeys key,
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers);
+                            OrthancStone::KeyboardModifiers modifiers);
 
     virtual bool HasAnimation() const
     {
--- a/Framework/Widgets/PanMouseTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/PanMouseTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   PanMouseTracker::PanMouseTracker(WorldSceneWidget& that,
                                    int x,
@@ -36,7 +36,7 @@
   }
     
 
-  void PanMouseTracker::Render(CairoContext& context,
+  void PanMouseTracker::Render(OrthancStone::CairoContext& context,
                                double zoom)
   {
     throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
--- a/Framework/Widgets/PanMouseTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/PanMouseTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "WorldSceneWidget.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class PanMouseTracker : public IWorldSceneMouseTracker
   {
@@ -48,7 +48,7 @@
     {
     }
 
-    virtual void Render(CairoContext& context,
+    virtual void Render(OrthancStone::CairoContext& context,
                         double zoom);
 
     virtual void MouseMove(int displayX,
--- a/Framework/Widgets/PanZoomMouseTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/PanZoomMouseTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 #include <Core/OrthancException.h>
 #include <math.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   Touch GetCenter(const std::vector<Touch>& touches)
   {
@@ -75,7 +75,7 @@
   }
 
 
-  void PanZoomMouseTracker::Render(CairoContext& context,
+  void PanZoomMouseTracker::Render(OrthancStone::CairoContext& context,
                                    double zoom)
   {
     throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
--- a/Framework/Widgets/PanZoomMouseTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/PanZoomMouseTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "WorldSceneWidget.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class PanZoomMouseTracker : public IWorldSceneMouseTracker
   {
@@ -52,7 +52,7 @@
     {
     }
 
-    virtual void Render(CairoContext& context,
+    virtual void Render(OrthancStone::CairoContext& context,
                         double zoom);
 
     virtual void MouseMove(int displayX,
--- a/Framework/Widgets/SliceViewerWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/SliceViewerWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -33,12 +33,12 @@
 
 static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits<double>::epsilon();
 
-namespace OrthancStone
+namespace Deprecated
 {
   class SliceViewerWidget::Scene : public boost::noncopyable
   {
   private:
-    CoordinateSystem3D            plane_;
+    OrthancStone::CoordinateSystem3D            plane_;
     double                        thickness_;
     size_t                        countMissing_;
     std::vector<ILayerRenderer*>  renderers_;
@@ -62,7 +62,7 @@
       }
     }
 
-    Scene(const CoordinateSystem3D& plane,
+    Scene(const OrthancStone::CoordinateSystem3D& plane,
           double thickness,
           size_t countLayers) :
       plane_(plane),
@@ -98,7 +98,7 @@
       countMissing_--;
     }
 
-    const CoordinateSystem3D& GetPlane() const
+    const OrthancStone::CoordinateSystem3D& GetPlane() const
     {
       return plane_;
     }
@@ -115,12 +115,12 @@
 
     unsigned int GetCountMissing() const
     {
-      return countMissing_;
+      return static_cast<unsigned int>(countMissing_);
     }
 
-    bool RenderScene(CairoContext& context,
+    bool RenderScene(OrthancStone::CairoContext& context,
                      const ViewportGeometry& view,
-                     const CoordinateSystem3D& viewportPlane)
+                     const OrthancStone::CoordinateSystem3D& viewportPlane)
     {
       bool fullQuality = true;
       cairo_t *cr = context.GetObject();
@@ -129,7 +129,7 @@
       {
         if (renderers_[i] != NULL)
         {
-          const CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane();
+          const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane();
           
           double x0, y0, x1, y1, x2, y2;
           viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin());
@@ -207,12 +207,12 @@
       }
     }
 
-    bool ContainsPlane(const CoordinateSystem3D& plane) const
+    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
     {
       bool isOpposite;
-      if (!GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                 plane.GetNormal(),
-                                                 plane_.GetNormal()))
+      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                               plane.GetNormal(),
+                                                               plane_.GetNormal()))
       {
         return false;
       }
@@ -256,12 +256,12 @@
   }
 
 
-  void SliceViewerWidget::GetLayerExtent(Extent2D& extent,
+  void SliceViewerWidget::GetLayerExtent(OrthancStone::Extent2D& extent,
                                          IVolumeSlicer& source) const
   {
     extent.Reset();
 
-    std::vector<Vector> points;
+    std::vector<OrthancStone::Vector> points;
     if (source.GetExtent(points, plane_))
     {
       for (size_t i = 0; i < points.size(); i++)
@@ -274,14 +274,14 @@
   }
 
 
-  Extent2D SliceViewerWidget::GetSceneExtent()
+  OrthancStone::Extent2D SliceViewerWidget::GetSceneExtent()
   {
-    Extent2D sceneExtent;
+    OrthancStone::Extent2D sceneExtent;
 
     for (size_t i = 0; i < layers_.size(); i++)
     {
       assert(layers_[i] != NULL);
-      Extent2D layerExtent;
+      OrthancStone::Extent2D layerExtent;
       GetLayerExtent(layerExtent, *layers_[i]);
 
       sceneExtent.Union(layerExtent);
@@ -291,7 +291,7 @@
   }
 
   
-  bool SliceViewerWidget::RenderScene(CairoContext& context,
+  bool SliceViewerWidget::RenderScene(OrthancStone::CairoContext& context,
                                       const ViewportGeometry& view)
   {
     if (currentScene_.get() != NULL)
@@ -323,7 +323,7 @@
 
   void SliceViewerWidget::UpdateLayer(size_t index,
                                       ILayerRenderer* renderer,
-                                      const CoordinateSystem3D& plane)
+                                      const OrthancStone::CoordinateSystem3D& plane)
   {
     LOG(INFO) << "Updating layer " << index;
     
@@ -364,7 +364,7 @@
   }
 
   
-  SliceViewerWidget::SliceViewerWidget(MessageBroker& broker, 
+  SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, 
                                        const std::string& name) :
     WorldSceneWidget(name),
     IObserver(broker),
@@ -385,16 +385,16 @@
   
   void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer)
   {
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage>
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage>
                                    (*this, &SliceViewerWidget::OnGeometryReady));
     // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryErrorMessage>(*this, &SliceViewerWidget::...));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::SliceContentChangedMessage>
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::SliceContentChangedMessage>
                                    (*this, &SliceViewerWidget::OnSliceChanged));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage>
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage>
                                    (*this, &SliceViewerWidget::OnContentChanged));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage>
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage>
                                    (*this, &SliceViewerWidget::OnLayerReady));
-    layer.RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage>
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage>
                                    (*this, &SliceViewerWidget::OnLayerError));
   }
 
@@ -504,13 +504,13 @@
   }
   
 
-  void SliceViewerWidget::SetSlice(const CoordinateSystem3D& plane)
+  void SliceViewerWidget::SetSlice(const OrthancStone::CoordinateSystem3D& plane)
   {
     LOG(INFO) << "Setting slice origin: (" << plane.GetOrigin()[0]
               << "," << plane.GetOrigin()[1]
               << "," << plane.GetOrigin()[2] << ")";
     
-    Slice displayedSlice(plane_, THIN_SLICE_THICKNESS);
+    Deprecated::Slice displayedSlice(plane_, THIN_SLICE_THICKNESS);
 
     //if (!displayedSlice.ContainsPlane(slice))
     {
--- a/Framework/Widgets/SliceViewerWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/SliceViewerWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -28,12 +28,12 @@
 
 #include <map>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class SliceViewerWidget :
     public WorldSceneWidget,
-    public IObserver,
-    public IObservable
+    public OrthancStone::IObserver,
+    public OrthancStone::IObservable
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryChangedMessage, SliceViewerWidget);
@@ -41,22 +41,22 @@
 
 
     // TODO - Use this message in ReferenceLineSource
-    class DisplayedSliceMessage : public OriginMessage<SliceViewerWidget>
+    class DisplayedSliceMessage : public OrthancStone::OriginMessage<SliceViewerWidget>
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      const Slice& slice_;
+      const Deprecated::Slice& slice_;
 
     public:
       DisplayedSliceMessage(SliceViewerWidget& origin,
-                            const Slice& slice) :
+                            const Deprecated::Slice& slice) :
         OriginMessage(origin),
         slice_(slice)
       {
       }
 
-      const Slice& GetSlice() const
+      const Deprecated::Slice& GetSlice() const
       {
         return slice_;
       }
@@ -74,7 +74,7 @@
     LayersIndex                  layersIndex_;
     std::vector<IVolumeSlicer*>  layers_;
     std::vector<RenderStyle>     styles_;
-    CoordinateSystem3D           plane_;
+    OrthancStone::CoordinateSystem3D           plane_;
     std::auto_ptr<Scene>         currentScene_;
     std::auto_ptr<Scene>         pendingScene_;
     std::vector<bool>            changedLayers_;
@@ -82,7 +82,7 @@
     bool LookupLayer(size_t& index /* out */,
                      const IVolumeSlicer& layer) const;
 
-    void GetLayerExtent(Extent2D& extent,
+    void GetLayerExtent(OrthancStone::Extent2D& extent,
                         IVolumeSlicer& source) const;
 
     void OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
@@ -100,20 +100,20 @@
     void ResetChangedLayers();
 
   public:
-    SliceViewerWidget(MessageBroker& broker, 
+    SliceViewerWidget(OrthancStone::MessageBroker& broker, 
                       const std::string& name);
 
-    virtual Extent2D GetSceneExtent();
+    virtual OrthancStone::Extent2D GetSceneExtent();
 
   protected:
-    virtual bool RenderScene(CairoContext& context,
+    virtual bool RenderScene(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view);
 
     void ResetPendingScene();
 
     void UpdateLayer(size_t index,
                      ILayerRenderer* renderer,
-                     const CoordinateSystem3D& plane);
+                     const OrthancStone::CoordinateSystem3D& plane);
 
     void InvalidateAllLayers();
 
@@ -138,9 +138,9 @@
     void SetLayerStyle(size_t layer,
                        const RenderStyle& style);
 
-    void SetSlice(const CoordinateSystem3D& plane);
+    void SetSlice(const OrthancStone::CoordinateSystem3D& plane);
 
-    const CoordinateSystem3D& GetSlice() const
+    const OrthancStone::CoordinateSystem3D& GetSlice() const
     {
       return plane_;
     }
--- a/Framework/Widgets/TestCairoWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/TestCairoWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <stdio.h>
 
 
-namespace OrthancStone
+namespace Deprecated
 {
   namespace Samples
   {
@@ -40,7 +40,7 @@
     }
 
 
-    bool TestCairoWidget::RenderCairo(CairoContext& context)
+    bool TestCairoWidget::RenderCairo(OrthancStone::CairoContext& context)
     {
       cairo_t* cr = context.GetObject();
 
@@ -60,7 +60,7 @@
     }
 
 
-    void TestCairoWidget::RenderMouseOverCairo(CairoContext& context,
+    void TestCairoWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context,
                                                int x,
                                                int y)
     {
@@ -96,10 +96,10 @@
     }
  
 
-    IMouseTracker* TestCairoWidget::CreateMouseTracker(MouseButton button,
+    IMouseTracker* TestCairoWidget::CreateMouseTracker(OrthancStone::MouseButton button,
                                                        int x,
                                                        int y,
-                                                       KeyboardModifiers modifiers,
+                                                       OrthancStone::KeyboardModifiers modifiers,
                                                        const std::vector<Touch>& touches)
     {
       UpdateStatusBar("Click");
@@ -107,18 +107,18 @@
     }
 
 
-    void TestCairoWidget::MouseWheel(MouseWheelDirection direction,
+    void TestCairoWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
                                      int x,
                                      int y,
-                                     KeyboardModifiers modifiers) 
+                                     OrthancStone::KeyboardModifiers modifiers) 
     {
-      UpdateStatusBar(direction == MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
+      UpdateStatusBar(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
     }
 
     
-    void TestCairoWidget::KeyPressed(KeyboardKeys key,
+    void TestCairoWidget::KeyPressed(OrthancStone::KeyboardKeys key,
                                      char keyChar,
-                                     KeyboardModifiers modifiers)
+                                     OrthancStone::KeyboardModifiers modifiers)
     {
       UpdateStatusBar("Key pressed: \"" + std::string(1, keyChar) + "\"");
     }
--- a/Framework/Widgets/TestCairoWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/TestCairoWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "CairoWidget.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   namespace Samples
   {
@@ -36,9 +36,9 @@
       bool          animate_;
 
     protected:
-      virtual bool RenderCairo(CairoContext& context);
+      virtual bool RenderCairo(OrthancStone::CairoContext& context);
 
-      virtual void RenderMouseOverCairo(CairoContext& context,
+      virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
                                         int x,
                                         int y);
 
@@ -48,20 +48,20 @@
       virtual void SetSize(unsigned int width, 
                            unsigned int height);
  
-      virtual IMouseTracker* CreateMouseTracker(MouseButton button,
+      virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
                                                 int x,
                                                 int y,
-                                                KeyboardModifiers modifiers,
+                                                OrthancStone::KeyboardModifiers modifiers,
                                                 const std::vector<Touch>& touches);
 
-      virtual void MouseWheel(MouseWheelDirection direction,
+      virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                               int x,
                               int y,
-                              KeyboardModifiers modifiers);
+                              OrthancStone::KeyboardModifiers modifiers);
     
-      virtual void KeyPressed(KeyboardKeys key,
+      virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                               char keyChar,
-                              KeyboardModifiers modifiers);
+                              OrthancStone::KeyboardModifiers modifiers);
 
       virtual bool HasAnimation() const
       {
--- a/Framework/Widgets/TestWorldSceneWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/TestWorldSceneWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 #include <math.h>
 #include <stdio.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   namespace Samples
   {
@@ -35,8 +35,8 @@
     public:
       virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                           const ViewportGeometry& view,
-                                                          MouseButton button,
-                                                          KeyboardModifiers modifiers,
+                                                          OrthancStone::MouseButton button,
+                                                          OrthancStone::KeyboardModifiers modifiers,
                                                           int viewportX,
                                                           int viewportY,
                                                           double x,
@@ -54,7 +54,7 @@
         return NULL;
       }
 
-      virtual void MouseOver(CairoContext& context,
+      virtual void MouseOver(OrthancStone::CairoContext& context,
                              WorldSceneWidget& widget,
                              const ViewportGeometry& view,
                              double x,
@@ -75,20 +75,20 @@
       }
 
       virtual void MouseWheel(WorldSceneWidget& widget,
-                              MouseWheelDirection direction,
-                              KeyboardModifiers modifiers,
+                              OrthancStone::MouseWheelDirection direction,
+                              OrthancStone::KeyboardModifiers modifiers,
                               IStatusBar* statusBar)
       {
         if (statusBar)
         {
-          statusBar->SetMessage(direction == MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
+          statusBar->SetMessage(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
         }
       }
 
       virtual void KeyPressed(WorldSceneWidget& widget,
-                              KeyboardKeys key,
+                              OrthancStone::KeyboardKeys key,
                               char keyChar,
-                              KeyboardModifiers modifiers,
+                              OrthancStone::KeyboardModifiers modifiers,
                               IStatusBar* statusBar)
       {
         if (statusBar)
@@ -99,7 +99,7 @@
     };
 
 
-    bool TestWorldSceneWidget::RenderScene(CairoContext& context,
+    bool TestWorldSceneWidget::RenderScene(OrthancStone::CairoContext& context,
                                            const ViewportGeometry& view)
     {
       cairo_t* cr = context.GetObject();
@@ -127,9 +127,9 @@
     }
 
 
-    Extent2D TestWorldSceneWidget::GetSceneExtent()
+    OrthancStone::Extent2D TestWorldSceneWidget::GetSceneExtent()
     {
-      return Extent2D(-10, -.5, 10, .5);
+      return OrthancStone::Extent2D(-10, -.5, 10, .5);
     }
 
 
--- a/Framework/Widgets/TestWorldSceneWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/TestWorldSceneWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 
 #include <memory>
 
-namespace OrthancStone
+namespace Deprecated
 {
   namespace Samples
   {
@@ -39,13 +39,13 @@
       unsigned int                count_;
 
     protected:
-      virtual bool RenderScene(CairoContext& context,
+      virtual bool RenderScene(OrthancStone::CairoContext& context,
                                const ViewportGeometry& view);
 
     public:
       TestWorldSceneWidget(const std::string& name, bool animate);
 
-      virtual Extent2D GetSceneExtent();
+      virtual OrthancStone::Extent2D GetSceneExtent();
 
       virtual bool HasAnimation() const
       {
--- a/Framework/Widgets/WidgetBase.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/WidgetBase.cpp	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 #include <Core/Images/ImageProcessing.h>
 #include <Core/Logging.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   void WidgetBase::NotifyContentChanged()
   {
@@ -69,7 +69,7 @@
   }
 
 
-  void WidgetBase::ClearBackgroundCairo(CairoContext& context) const
+  void WidgetBase::ClearBackgroundCairo(OrthancStone::CairoContext& context) const
   {
     // Clear the background using Cairo
 
@@ -86,8 +86,8 @@
 
   void WidgetBase::ClearBackgroundCairo(Orthanc::ImageAccessor& target) const
   {
-    CairoSurface surface(target, false /* no alpha */);
-    CairoContext context(surface);
+    OrthancStone::CairoSurface surface(target, false /* no alpha */);
+    OrthancStone::CairoContext context(surface);
     ClearBackgroundCairo(context);
   }
 
--- a/Framework/Widgets/WidgetBase.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/WidgetBase.h	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 #include "../Viewport/CairoContext.h"
 #include "../Viewport/WidgetViewport.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WidgetBase : public IWidget
   {
@@ -42,7 +42,7 @@
   protected:
     void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const;
 
-    void ClearBackgroundCairo(CairoContext& context) const;
+    void ClearBackgroundCairo(OrthancStone::CairoContext& context) const;
 
     void ClearBackgroundCairo(Orthanc::ImageAccessor& target) const;
 
--- a/Framework/Widgets/WorldSceneWidget.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/WorldSceneWidget.cpp	Tue May 21 13:25:58 2019 +0200
@@ -32,7 +32,7 @@
 #include <memory>
 #include <cassert>
 
-namespace OrthancStone
+namespace Deprecated
 {
   // this is an adapter between a IWorldSceneMouseTracker
   // that is tracking a mouse in scene coordinates/mm and
@@ -60,8 +60,8 @@
     {
       if (tracker_->HasRender())
       {
-        CairoSurface surface(target, false /* no alpha */);
-        CairoContext context(surface);
+        OrthancStone::CairoSurface surface(target, false /* no alpha */);
+        OrthancStone::CairoContext context(surface);
         view_.ApplyTransform(context);
         tracker_->Render(context, view_.GetZoom());
       }
@@ -83,22 +83,26 @@
       for (size_t t = 0; t < displayTouches.size(); t++)
       {
         double sx, sy;
-        view_.MapPixelCenterToScene(sx, sy, (int)displayTouches[t].x, (int)displayTouches[t].y);
-        sceneTouches.push_back(Touch(sx, sy));
+        
+        view_.MapPixelCenterToScene(
+          sx, sy, (int)displayTouches[t].x, (int)displayTouches[t].y);
+        
+        sceneTouches.push_back(
+          Touch(static_cast<float>(sx), static_cast<float>(sy)));
       }
       tracker_->MouseMove(x, y, sceneX, sceneY, displayTouches, sceneTouches);
     }
   };
 
 
-  bool WorldSceneWidget::RenderCairo(CairoContext& context)
+  bool WorldSceneWidget::RenderCairo(OrthancStone::CairoContext& context)
   {
     view_.ApplyTransform(context);
     return RenderScene(context, view_);
   }
 
 
-  void WorldSceneWidget::RenderMouseOverCairo(CairoContext& context,
+  void WorldSceneWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context,
                                               int x,
                                               int y)
   {
@@ -152,10 +156,10 @@
   }
 
 
-  IMouseTracker* WorldSceneWidget::CreateMouseTracker(MouseButton button,
+  IMouseTracker* WorldSceneWidget::CreateMouseTracker(OrthancStone::MouseButton button,
                                                       int x,
                                                       int y,
-                                                      KeyboardModifiers modifiers,
+                                                      OrthancStone::KeyboardModifiers modifiers,
                                                       const std::vector<Touch>& touches)
   {
     double sceneX, sceneY;
@@ -185,10 +189,10 @@
       {
         switch (button)
         {
-          case MouseButton_Middle:
+          case OrthancStone::MouseButton_Middle:
             return new SceneMouseTracker(view_, new PanMouseTracker(*this, x, y));
 
-          case MouseButton_Right:
+          case OrthancStone::MouseButton_Right:
             return new SceneMouseTracker(view_, new ZoomMouseTracker(*this, x, y));
 
           default:
@@ -203,10 +207,10 @@
   }
 
 
-  void WorldSceneWidget::MouseWheel(MouseWheelDirection direction,
+  void WorldSceneWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
                                     int x,
                                     int y,
-                                    KeyboardModifiers modifiers)
+                                    OrthancStone::KeyboardModifiers modifiers)
   {
     if (interactor_)
     {
@@ -215,9 +219,9 @@
   }
 
 
-  void WorldSceneWidget::KeyPressed(KeyboardKeys key,
+  void WorldSceneWidget::KeyPressed(OrthancStone::KeyboardKeys key,
                                     char keyChar,
-                                    KeyboardModifiers modifiers)
+                                    OrthancStone::KeyboardModifiers modifiers)
   {
     if (interactor_)
     {
--- a/Framework/Widgets/WorldSceneWidget.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/WorldSceneWidget.h	Tue May 21 13:25:58 2019 +0200
@@ -26,7 +26,7 @@
 
 #include "../Toolbox/ViewportGeometry.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WorldSceneWidget : public CairoWidget
   {
@@ -38,16 +38,16 @@
     bool                   hasDefaultMouseEvents_;
 
   protected:
-    virtual Extent2D GetSceneExtent() = 0;
+    virtual OrthancStone::Extent2D GetSceneExtent() = 0;
 
-    virtual bool RenderScene(CairoContext& context,
+    virtual bool RenderScene(OrthancStone::CairoContext& context,
                              const ViewportGeometry& view) = 0;
 
     // From CairoWidget
-    virtual bool RenderCairo(CairoContext& context);
+    virtual bool RenderCairo(OrthancStone::CairoContext& context);
 
     // From CairoWidget
-    virtual void RenderMouseOverCairo(CairoContext& context,
+    virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
                                       int x,
                                       int y);
 
@@ -85,19 +85,19 @@
 
     virtual void FitContent();
 
-    virtual IMouseTracker* CreateMouseTracker(MouseButton button,
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
                                               int x,
                                               int y,
-                                              KeyboardModifiers modifiers,
+                                              OrthancStone::KeyboardModifiers modifiers,
                                               const std::vector<Touch>& touches);
 
-    virtual void MouseWheel(MouseWheelDirection direction,
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
                             int x,
                             int y,
-                            KeyboardModifiers modifiers);
+                            OrthancStone::KeyboardModifiers modifiers);
 
-    virtual void KeyPressed(KeyboardKeys key,
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers);
+                            OrthancStone::KeyboardModifiers modifiers);
   };
 }
--- a/Framework/Widgets/ZoomMouseTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/ZoomMouseTracker.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,7 +24,7 @@
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that,
                                      int x,
@@ -51,7 +51,7 @@
   }
     
 
-  void ZoomMouseTracker::Render(CairoContext& context,
+  void ZoomMouseTracker::Render(OrthancStone::CairoContext& context,
                                 double zoom)
   {
     throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
--- a/Framework/Widgets/ZoomMouseTracker.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/Widgets/ZoomMouseTracker.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "WorldSceneWidget.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class ZoomMouseTracker : public IWorldSceneMouseTracker
   {
@@ -51,7 +51,7 @@
     {
     }
 
-    virtual void Render(CairoContext& context,
+    virtual void Render(OrthancStone::CairoContext& context,
                         double zoom);
 
     virtual void MouseMove(int displayX,
--- a/Framework/dev.h	Thu May 16 19:10:38 2019 +0200
+++ b/Framework/dev.h	Tue May 21 13:25:58 2019 +0200
@@ -38,16 +38,16 @@
 #include <boost/math/special_functions/round.hpp>
 
 
-namespace OrthancStone
+namespace Deprecated
 {
   // TODO: Handle errors while loading
   class OrthancVolumeImage :
     public ISlicedVolume,
-    public IObserver
+    public OrthancStone::IObserver
   {
   private:
     OrthancSlicesLoader           loader_;
-    std::auto_ptr<ImageBuffer3D>  image_;
+    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
     std::auto_ptr<DownloadStack>  downloadStack_;
     bool                          computeRange_;
     size_t                        pendingSlices_;
@@ -59,7 +59,7 @@
       unsigned int slice;
       if (downloadStack_->Pop(slice))
       {
-        loader_.ScheduleLoadSliceImage(slice, SliceImageQuality_Jpeg90);
+        loader_.ScheduleLoadSliceImage(slice, OrthancStone::SliceImageQuality_Jpeg90);
       }
     }
 
@@ -67,8 +67,8 @@
     static bool IsCompatible(const Slice& a,
                              const Slice& b)
     {
-      if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(),
-                                       b.GetGeometry().GetNormal()))
+      if (!OrthancStone::GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(),
+                                                     b.GetGeometry().GetNormal()))
       {
         LOG(ERROR) << "A slice in the volume image is not parallel to the others.";
         return false;
@@ -87,8 +87,8 @@
         return false;
       }
 
-      if (!LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
-          !LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
+      if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
+          !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
       {
         LOG(ERROR) << "The pixel spacing of the slices change across the volume image";
         return false;
@@ -141,8 +141,8 @@
 
       for (size_t i = 1; i < loader_.GetSlicesCount(); i++)
       {
-        if (!LinearAlgebra::IsNear(spacingZ, GetDistance(loader_.GetSlice(i - 1), loader_.GetSlice(i)),
-                                   0.001 /* this is expressed in mm */))
+        if (!OrthancStone::LinearAlgebra::IsNear(spacingZ, GetDistance(loader_.GetSlice(i - 1), loader_.GetSlice(i)),
+                                                 0.001 /* this is expressed in mm */))
         {
           LOG(ERROR) << "The distance between successive slices is not constant in a volume image";
           BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
@@ -156,10 +156,10 @@
       LOG(INFO) << "Creating a volume image of size " << width << "x" << height
                 << "x" << loader_.GetSlicesCount() << " in " << Orthanc::EnumerationToString(format);
 
-      image_.reset(new ImageBuffer3D(format, width, height, static_cast<unsigned int>(loader_.GetSlicesCount()), computeRange_));
-      image_->SetAxialGeometry(loader_.GetSlice(0).GetGeometry());
-      image_->SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(),
-                                 loader_.GetSlice(0).GetPixelSpacingY(), spacingZ);
+      image_.reset(new OrthancStone::ImageBuffer3D(format, width, height, static_cast<unsigned int>(loader_.GetSlicesCount()), computeRange_));
+      image_->GetGeometry().SetAxialGeometry(loader_.GetSlice(0).GetGeometry());
+      image_->GetGeometry().SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(),
+                                               loader_.GetSlice(0).GetPixelSpacingY(), spacingZ);
       image_->Clear();
 
       downloadStack_.reset(new DownloadStack(static_cast<unsigned int>(loader_.GetSlicesCount())));
@@ -190,12 +190,12 @@
       assert(&message.GetOrigin() == &loader_);
 
       {
-        ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, message.GetSliceIndex());
+        OrthancStone::ImageBuffer3D::SliceWriter writer(*image_, OrthancStone::VolumeProjection_Axial, message.GetSliceIndex());
         Orthanc::ImageProcessing::Copy(writer.GetAccessor(), message.GetImage());
       }
 
       BroadcastMessage(ISlicedVolume::SliceContentChangedMessage
-                  (*this, message.GetSliceIndex(), message.GetSlice()));
+                       (*this, message.GetSliceIndex(), message.GetSlice()));
 
       if (pendingSlices_ == 1)
       {
@@ -221,7 +221,7 @@
 
 
   public:
-    OrthancVolumeImage(MessageBroker& broker,
+    OrthancVolumeImage(OrthancStone::MessageBroker& broker,
                        OrthancApiClient& orthanc,
                        bool computeRange) :
       ISlicedVolume(broker),
@@ -231,19 +231,19 @@
       pendingSlices_(0)
     {
       loader_.RegisterObserverCallback(
-        new Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryReadyMessage>
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryReadyMessage>
         (*this, &OrthancVolumeImage::OnSliceGeometryReady));
 
       loader_.RegisterObserverCallback(
-        new Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryErrorMessage>
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryErrorMessage>
         (*this, &OrthancVolumeImage::OnSliceGeometryError));
 
       loader_.RegisterObserverCallback(
-        new Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageReadyMessage>
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageReadyMessage>
         (*this, &OrthancVolumeImage::OnSliceImageReady));
 
       loader_.RegisterObserverCallback(
-        new Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageErrorMessage>
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageErrorMessage>
         (*this, &OrthancVolumeImage::OnSliceImageError));
     }
 
@@ -273,7 +273,7 @@
       return loader_.GetSlice(index);
     }
 
-    ImageBuffer3D& GetImage() const
+    OrthancStone::ImageBuffer3D& GetImage() const
     {
       if (image_.get() == NULL)
       {
@@ -310,7 +310,7 @@
     double               pixelSpacingX_;
     double               pixelSpacingY_;
     double               sliceThickness_;
-    CoordinateSystem3D   reference_;
+    OrthancStone::CoordinateSystem3D   reference_;
     DicomFrameConverter  converter_;
 
     double ComputeAxialThickness(const OrthancVolumeImage& volume) const
@@ -371,13 +371,13 @@
       pixelSpacingY_ = axialThickness;
       sliceThickness_ = axial.GetPixelSpacingY();
 
-      Vector origin = axial.GetGeometry().GetOrigin();
+      OrthancStone::Vector origin = axial.GetGeometry().GetOrigin();
       origin += (static_cast<double>(volume.GetSlicesCount() - 1) *
-                axialThickness * axial.GetGeometry().GetNormal());
+                 axialThickness * axial.GetGeometry().GetNormal());
 
-      reference_ = CoordinateSystem3D(origin,
-                                      axial.GetGeometry().GetAxisX(),
-                                      - axial.GetGeometry().GetNormal());
+      reference_ = OrthancStone::CoordinateSystem3D(origin,
+                                                    axial.GetGeometry().GetAxisX(),
+                                                    - axial.GetGeometry().GetNormal());
     }
 
     void SetupSagittal(const OrthancVolumeImage& volume)
@@ -393,18 +393,18 @@
       pixelSpacingY_ = axialThickness;
       sliceThickness_ = axial.GetPixelSpacingX();
 
-      Vector origin = axial.GetGeometry().GetOrigin();
+      OrthancStone::Vector origin = axial.GetGeometry().GetOrigin();
       origin += (static_cast<double>(volume.GetSlicesCount() - 1) *
-                axialThickness * axial.GetGeometry().GetNormal());
+                 axialThickness * axial.GetGeometry().GetNormal());
 
-      reference_ = CoordinateSystem3D(origin,
-                                      axial.GetGeometry().GetAxisY(),
-                                      axial.GetGeometry().GetNormal());
+      reference_ = OrthancStone::CoordinateSystem3D(origin,
+                                                    axial.GetGeometry().GetAxisY(),
+                                                    axial.GetGeometry().GetNormal());
     }
 
   public:
     VolumeImageGeometry(const OrthancVolumeImage& volume,
-                        VolumeProjection projection)
+                        OrthancStone::VolumeProjection projection)
     {
       if (volume.GetSlicesCount() == 0)
       {
@@ -415,20 +415,20 @@
 
       switch (projection)
       {
-      case VolumeProjection_Axial:
-        SetupAxial(volume);
-        break;
+        case OrthancStone::VolumeProjection_Axial:
+          SetupAxial(volume);
+          break;
 
-      case VolumeProjection_Coronal:
-        SetupCoronal(volume);
-        break;
+        case OrthancStone::VolumeProjection_Coronal:
+          SetupCoronal(volume);
+          break;
 
-      case VolumeProjection_Sagittal:
-        SetupSagittal(volume);
-        break;
+        case OrthancStone::VolumeProjection_Sagittal:
+          SetupSagittal(volume);
+          break;
 
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
       }
     }
 
@@ -437,18 +437,18 @@
       return depth_;
     }
 
-    const Vector& GetNormal() const
+    const OrthancStone::Vector& GetNormal() const
     {
       return reference_.GetNormal();
     }
 
     bool LookupSlice(size_t& index,
-                     const CoordinateSystem3D& slice) const
+                     const OrthancStone::CoordinateSystem3D& slice) const
     {
       bool opposite;
-      if (!GeometryToolbox::IsParallelOrOpposite(opposite,
-                                                 reference_.GetNormal(),
-                                                 slice.GetNormal()))
+      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite,
+                                                               reference_.GetNormal(),
+                                                               slice.GetNormal()))
       {
         return false;
       }
@@ -459,7 +459,7 @@
       int s = static_cast<int>(boost::math::iround(z));
 
       if (s < 0 ||
-        s >= static_cast<int>(depth_))
+          s >= static_cast<int>(depth_))
       {
         return false;
       }
@@ -478,10 +478,10 @@
       }
       else
       {
-        CoordinateSystem3D origin(reference_.GetOrigin() +
-                                  static_cast<double>(slice) * sliceThickness_ * reference_.GetNormal(),
-                                  reference_.GetAxisX(),
-                                  reference_.GetAxisY());
+        OrthancStone::CoordinateSystem3D origin(reference_.GetOrigin() +
+                                                static_cast<double>(slice) * sliceThickness_ * reference_.GetNormal(),
+                                                reference_.GetAxisX(),
+                                                reference_.GetAxisY());
 
         return new Slice(origin, pixelSpacingX_, pixelSpacingY_, sliceThickness_,
                          width_, height_, converter_);
@@ -493,7 +493,7 @@
 
   class VolumeImageMPRSlicer :
     public IVolumeSlicer,
-    public IObserver
+    public OrthancStone::IObserver
   {
   private:
     class RendererFactory : public LayerReadyMessage::IRendererFactory
@@ -507,9 +507,9 @@
       RendererFactory(const Orthanc::ImageAccessor& frame,
                       const Slice& slice,
                       bool isFullQuality) :
-                      frame_(frame),
-                      slice_(slice),
-                      isFullQuality_(isFullQuality)
+        frame_(frame),
+        slice_(slice),
+        isFullQuality_(isFullQuality)
       {
       }
 
@@ -536,9 +536,9 @@
       assert(&message.GetOrigin() == &volume_);
 
       // 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));
+      axialGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Axial));
+      coronalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Coronal));
+      sagittalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Sagittal));
 
       BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
     }
@@ -567,7 +567,7 @@
       BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
     }
 
-    const VolumeImageGeometry& GetProjectionGeometry(VolumeProjection projection)
+    const VolumeImageGeometry& GetProjectionGeometry(OrthancStone::VolumeProjection projection)
     {
       if (!IsGeometryReady())
       {
@@ -576,45 +576,45 @@
 
       switch (projection)
       {
-      case VolumeProjection_Axial:
-        return *axialGeometry_;
+        case OrthancStone::VolumeProjection_Axial:
+          return *axialGeometry_;
 
-      case VolumeProjection_Sagittal:
-        return *sagittalGeometry_;
+        case OrthancStone::VolumeProjection_Sagittal:
+          return *sagittalGeometry_;
 
-      case VolumeProjection_Coronal:
-        return *coronalGeometry_;
+        case OrthancStone::VolumeProjection_Coronal:
+          return *coronalGeometry_;
 
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
       }
     }
 
 
-    bool DetectProjection(VolumeProjection& projection,
-                          const CoordinateSystem3D& viewportSlice)
+    bool DetectProjection(OrthancStone::VolumeProjection& projection,
+                          const OrthancStone::CoordinateSystem3D& viewportSlice)
     {
       bool isOpposite;  // Ignored
 
-      if (GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                viewportSlice.GetNormal(),
-                                                axialGeometry_->GetNormal()))
+      if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                              viewportSlice.GetNormal(),
+                                                              axialGeometry_->GetNormal()))
       {
-        projection = VolumeProjection_Axial;
+        projection = OrthancStone::VolumeProjection_Axial;
         return true;
       }
-      else if (GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                     viewportSlice.GetNormal(),
-                                                     sagittalGeometry_->GetNormal()))
+      else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                                   viewportSlice.GetNormal(),
+                                                                   sagittalGeometry_->GetNormal()))
       {
-        projection = VolumeProjection_Sagittal;
+        projection = OrthancStone::VolumeProjection_Sagittal;
         return true;
       }
-      else if (GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                     viewportSlice.GetNormal(),
-                                                     coronalGeometry_->GetNormal()))
+      else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                                   viewportSlice.GetNormal(),
+                                                                   coronalGeometry_->GetNormal()))
       {
-        projection = VolumeProjection_Coronal;
+        projection = OrthancStone::VolumeProjection_Coronal;
         return true;
       }
       else
@@ -625,33 +625,33 @@
 
 
   public:
-    VolumeImageMPRSlicer(MessageBroker& broker,
+    VolumeImageMPRSlicer(OrthancStone::MessageBroker& broker,
                          OrthancVolumeImage&  volume) :
-                         IVolumeSlicer(broker),
-                         IObserver(broker),
-                         volume_(volume)
+      IVolumeSlicer(broker),
+      IObserver(broker),
+      volume_(volume)
     {
       volume_.RegisterObserverCallback(
-        new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage>
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage>
         (*this, &VolumeImageMPRSlicer::OnGeometryReady));
 
       volume_.RegisterObserverCallback(
-        new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryErrorMessage>
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryErrorMessage>
         (*this, &VolumeImageMPRSlicer::OnGeometryError));
 
       volume_.RegisterObserverCallback(
-        new Callable<VolumeImageMPRSlicer, ISlicedVolume::ContentChangedMessage>
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::ContentChangedMessage>
         (*this, &VolumeImageMPRSlicer::OnContentChanged));
 
       volume_.RegisterObserverCallback(
-        new Callable<VolumeImageMPRSlicer, ISlicedVolume::SliceContentChangedMessage>
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::SliceContentChangedMessage>
         (*this, &VolumeImageMPRSlicer::OnSliceContentChanged));
     }
 
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
     {
-      VolumeProjection projection;
+      OrthancStone::VolumeProjection projection;
 
       if (!IsGeometryReady() ||
           !DetectProjection(projection, viewportSlice))
@@ -669,9 +669,9 @@
       }
     }
 
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
     {
-      VolumeProjection projection;
+      OrthancStone::VolumeProjection projection;
 
       if (IsGeometryReady() &&
           DetectProjection(projection, viewportSlice))
@@ -687,7 +687,7 @@
           std::auto_ptr<Orthanc::Image> frame;
 
           {
-            ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast<unsigned int>(closest));
+            OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast<unsigned int>(closest));
 
             // TODO Transfer ownership if non-axial, to avoid memcpy
             frame.reset(Orthanc::Image::Clone(reader.GetAccessor()));
@@ -703,7 +703,7 @@
       }
 
       // Error
-      CoordinateSystem3D slice;
+      OrthancStone::CoordinateSystem3D slice;
       BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, slice));
     }
   };
@@ -711,11 +711,11 @@
 
   class VolumeImageInteractor :
     public IWorldSceneInteractor,
-    public IObserver
+    public OrthancStone::IObserver
   {
   private:
     SliceViewerWidget&                  widget_;
-    VolumeProjection                    projection_;
+    OrthancStone::VolumeProjection      projection_;
     std::auto_ptr<VolumeImageGeometry>  slices_;
     size_t                              slice_;
 
@@ -736,8 +736,8 @@
 
     virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                         const ViewportGeometry& view,
-                                                        MouseButton button,
-                                                        KeyboardModifiers modifiers,
+                                                        OrthancStone::MouseButton button,
+                                                        OrthancStone::KeyboardModifiers modifiers,
                                                         int viewportX,
                                                         int viewportY,
                                                         double x,
@@ -748,7 +748,7 @@
       return  NULL;
     }
 
-    virtual void MouseOver(CairoContext& context,
+    virtual void MouseOver(OrthancStone::CairoContext& context,
                            WorldSceneWidget& widget,
                            const ViewportGeometry& view,
                            double x,
@@ -758,57 +758,57 @@
     }
 
     virtual void MouseWheel(WorldSceneWidget& widget,
-                            MouseWheelDirection direction,
-                            KeyboardModifiers modifiers,
+                            OrthancStone::MouseWheelDirection direction,
+                            OrthancStone::KeyboardModifiers modifiers,
                             IStatusBar* statusBar) ORTHANC_OVERRIDE
     {
-      int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
+      int scale = (modifiers & OrthancStone::KeyboardModifiers_Control ? 10 : 1);
 
       switch (direction)
       {
-      case MouseWheelDirection_Up:
-        OffsetSlice(-scale);
-        break;
+        case OrthancStone::MouseWheelDirection_Up:
+          OffsetSlice(-scale);
+          break;
 
-      case MouseWheelDirection_Down:
-        OffsetSlice(scale);
-        break;
+        case OrthancStone::MouseWheelDirection_Down:
+          OffsetSlice(scale);
+          break;
 
-      default:
-        break;
+        default:
+          break;
       }
     }
 
     virtual void KeyPressed(WorldSceneWidget& widget,
-                            KeyboardKeys key,
+                            OrthancStone::KeyboardKeys key,
                             char keyChar,
-                            KeyboardModifiers modifiers,
+                            OrthancStone::KeyboardModifiers modifiers,
                             IStatusBar* statusBar) ORTHANC_OVERRIDE
     {
       switch (keyChar)
       {
-      case 's':
-        widget.FitContent();
-        break;
+        case 's':
+          widget.FitContent();
+          break;
 
-      default:
-        break;
+        default:
+          break;
       }
     }
 
   public:
-    VolumeImageInteractor(MessageBroker& broker,
+    VolumeImageInteractor(OrthancStone::MessageBroker& broker,
                           OrthancVolumeImage& volume,
                           SliceViewerWidget& widget,
-                          VolumeProjection projection) :
-                          IObserver(broker),
-                          widget_(widget),
-                          projection_(projection)
+                          OrthancStone::VolumeProjection projection) :
+      IObserver(broker),
+      widget_(widget),
+      projection_(projection)
     {
       widget.SetInteractor(*this);
 
       volume.RegisterObserverCallback(
-        new Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage>
+        new OrthancStone::Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage>
         (*this, &VolumeImageInteractor::OnGeometryReady));
     }
 
@@ -876,14 +876,14 @@
       double                     y1_;
       double                     x2_;
       double                     y2_;
-      const CoordinateSystem3D&  slice_;
+      const OrthancStone::CoordinateSystem3D&  slice_;
 
     public:
       RendererFactory(double x1,
                       double y1,
                       double x2,
                       double y2,
-                      const CoordinateSystem3D& slice) :
+                      const OrthancStone::CoordinateSystem3D& slice) :
         x1_(x1),
         y1_(y1),
         x2_(x2),
@@ -901,7 +901,7 @@
     SliceViewerWidget&  otherPlane_;
 
   public:
-    ReferenceLineSource(MessageBroker& broker,
+    ReferenceLineSource(OrthancStone::MessageBroker& broker,
                         SliceViewerWidget&  otherPlane) :
       IVolumeSlicer(broker),
       otherPlane_(otherPlane)
@@ -909,24 +909,24 @@
       BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
     }
 
-    virtual bool GetExtent(std::vector<Vector>& points,
-                           const CoordinateSystem3D& viewportSlice)
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice)
     {
       return false;
     }
 
-    virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice)
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
     {
       Slice reference(viewportSlice, 0.001);
 
-      Vector p, d;
+      OrthancStone::Vector p, d;
 
-      const CoordinateSystem3D& slice = otherPlane_.GetSlice();
+      const OrthancStone::CoordinateSystem3D& slice = otherPlane_.GetSlice();
 
       // Compute the line of intersection between the two slices
-      if (!GeometryToolbox::IntersectTwoPlanes(p, d,
-                                               slice.GetOrigin(), slice.GetNormal(),
-                                               viewportSlice.GetOrigin(), viewportSlice.GetNormal()))
+      if (!OrthancStone::GeometryToolbox::IntersectTwoPlanes(p, d,
+                                                             slice.GetOrigin(), slice.GetNormal(),
+                                                             viewportSlice.GetOrigin(), viewportSlice.GetNormal()))
       {
         // The two slice are parallel, don't try and display the intersection
         BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry()));
@@ -937,12 +937,12 @@
         viewportSlice.ProjectPoint(x1, y1, p);
         viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d);
 
-        const Extent2D extent = otherPlane_.GetSceneExtent();
+        const OrthancStone::Extent2D extent = otherPlane_.GetSceneExtent();
 
-        if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2,
-                                                 x1, y1, x2, y2,
-                                                 extent.GetX1(), extent.GetY1(),
-                                                 extent.GetX2(), extent.GetY2()))
+        if (OrthancStone::GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2,
+                                                               x1, y1, x2, y2,
+                                                               extent.GetX1(), extent.GetY1(),
+                                                               extent.GetX2(), extent.GetY2()))
         {
           RendererFactory factory(x1, y1, x2, y2, slice);
           BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, reference.GetGeometry()));
--- a/Platforms/Generic/DelayedCallCommand.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/DelayedCallCommand.cpp	Tue May 21 13:25:58 2019 +0200
@@ -24,13 +24,13 @@
 
 #include <iostream>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  DelayedCallCommand::DelayedCallCommand(MessageBroker& broker,
-                                         MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
+  DelayedCallCommand::DelayedCallCommand(OrthancStone::MessageBroker& broker,
+                                         OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
                                          unsigned int timeoutInMs,
                                          Orthanc::IDynamicObject* payload /* takes ownership */,
-                                         NativeStoneApplicationContext& context
+                                         OrthancStone::NativeStoneApplicationContext& context
                                          ) :
     IObservable(broker),
     callback_(callback),
@@ -55,7 +55,7 @@
     // We want to make sure that, i.e, the UpdateThread is not
     // triggered while we are updating the "model" with the result of
     // an OracleCommand
-    NativeStoneApplicationContext::GlobalMutexLocker lock(context_);
+    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker lock(context_);
 
     if (callback_.get() != NULL)
     {
--- a/Platforms/Generic/DelayedCallCommand.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/DelayedCallCommand.h	Tue May 21 13:25:58 2019 +0200
@@ -30,23 +30,23 @@
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  class DelayedCallCommand : public IOracleCommand, IObservable
+  class DelayedCallCommand : public IOracleCommand, OrthancStone::IObservable
   {
   protected:
-    std::auto_ptr<MessageHandler<IDelayedCallExecutor::TimeoutMessage> >  callback_;
+    std::auto_ptr<OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage> >  callback_;
     std::auto_ptr<Orthanc::IDynamicObject>  payload_;
-    NativeStoneApplicationContext&          context_;
+    OrthancStone::NativeStoneApplicationContext&          context_;
     boost::posix_time::ptime                expirationTimePoint_;
     unsigned int                            timeoutInMs_;
 
   public:
-    DelayedCallCommand(MessageBroker& broker,
-                       MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
+    DelayedCallCommand(OrthancStone::MessageBroker& broker,
+                       OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
                        unsigned int timeoutInMs,
                        Orthanc::IDynamicObject* payload /* takes ownership */,
-                       NativeStoneApplicationContext& context
+                       OrthancStone::NativeStoneApplicationContext& context
                        );
 
     virtual void Execute();
--- a/Platforms/Generic/IOracleCommand.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/IOracleCommand.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include <Core/IDynamicObject.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class IOracleCommand : public Orthanc::IDynamicObject
   {
--- a/Platforms/Generic/Oracle.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/Oracle.cpp	Tue May 21 13:25:58 2019 +0200
@@ -29,7 +29,7 @@
 #include <stdio.h>
 #include <boost/thread/mutex.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class Oracle::PImpl
   {
--- a/Platforms/Generic/Oracle.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/Oracle.h	Tue May 21 13:25:58 2019 +0200
@@ -25,7 +25,7 @@
 
 #include <boost/shared_ptr.hpp>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class Oracle : public boost::noncopyable
   {
--- a/Platforms/Generic/OracleDelayedCallExecutor.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/OracleDelayedCallExecutor.h	Tue May 21 13:25:58 2019 +0200
@@ -26,26 +26,26 @@
 #include "../../Applications/Generic/NativeStoneApplicationContext.h"
 #include "DelayedCallCommand.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   // The OracleTimeout executes callbacks after a delay.
   class OracleDelayedCallExecutor : public IDelayedCallExecutor
   {
   private:
     Oracle&                        oracle_;
-    NativeStoneApplicationContext& context_;
+    OrthancStone::NativeStoneApplicationContext& context_;
 
   public:
-    OracleDelayedCallExecutor(MessageBroker& broker,
+    OracleDelayedCallExecutor(OrthancStone::MessageBroker& broker,
                               Oracle& oracle,
-                              NativeStoneApplicationContext& context) :
+                              OrthancStone::NativeStoneApplicationContext& context) :
       IDelayedCallExecutor(broker),
       oracle_(oracle),
       context_(context)
     {
     }
 
-    virtual void Schedule(MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
+    virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
                           unsigned int timeoutInMs = 1000)
     {
       oracle_.Submit(new DelayedCallCommand(broker_, callback, timeoutInMs, NULL, context_));
--- a/Platforms/Generic/OracleWebService.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/OracleWebService.cpp	Tue May 21 13:25:58 2019 +0200
@@ -22,24 +22,24 @@
 #include "OracleWebService.h"
 #include "../../Framework/Toolbox/IWebService.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
 
 
-  class OracleWebService::WebServiceCachedGetCommand : public IOracleCommand, IObservable
+  class OracleWebService::WebServiceCachedGetCommand : public IOracleCommand, OrthancStone::IObservable
   {
   protected:
-    std::auto_ptr<MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
+    std::auto_ptr<OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
     std::auto_ptr<Orthanc::IDynamicObject>                                  payload_;
     boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage>      cachedMessage_;
-    NativeStoneApplicationContext&                                          context_;
+    OrthancStone::NativeStoneApplicationContext&                                          context_;
 
   public:
-    WebServiceCachedGetCommand(MessageBroker& broker,
-                               MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+    WebServiceCachedGetCommand(OrthancStone::MessageBroker& broker,
+                               OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                                boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedMessage,
                                Orthanc::IDynamicObject* payload /* takes ownership */,
-                               NativeStoneApplicationContext& context
+                               OrthancStone::NativeStoneApplicationContext& context
                                ) :
       IObservable(broker),
       successCallback_(successCallback),
@@ -59,7 +59,7 @@
       // We want to make sure that, i.e, the UpdateThread is not
       // triggered while we are updating the "model" with the result of
       // a WebServiceCommand
-      NativeStoneApplicationContext::GlobalMutexLocker lock(context_);
+      OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker lock(context_);
 
       IWebService::HttpRequestSuccessMessage successMessage(cachedMessage_->GetUri(),
                                                             cachedMessage_->GetAnswer(),
@@ -73,7 +73,7 @@
 
   void OracleWebService::NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedMessage,
                                                 Orthanc::IDynamicObject* payload, // takes ownership
-                                                MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback)
+                                                OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback)
   {
     oracle_.Submit(new WebServiceCachedGetCommand(GetBroker(), successCallback, cachedMessage, payload, context_));
   }
--- a/Platforms/Generic/OracleWebService.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/OracleWebService.h	Tue May 21 13:25:58 2019 +0200
@@ -28,7 +28,7 @@
 #include "WebServiceDeleteCommand.h"
 #include "../../Applications/Generic/NativeStoneApplicationContext.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   // The OracleWebService performs HTTP requests in a native environment.
   // It uses a thread pool to handle multiple HTTP requests in a same time.
@@ -37,16 +37,16 @@
   {
   private:
     Oracle&                        oracle_;
-    NativeStoneApplicationContext& context_;
+    OrthancStone::NativeStoneApplicationContext& context_;
     Orthanc::WebServiceParameters  parameters_;
 
     class WebServiceCachedGetCommand;
 
   public:
-    OracleWebService(MessageBroker& broker,
+    OracleWebService(OrthancStone::MessageBroker& broker,
                      Oracle& oracle,
                      const Orthanc::WebServiceParameters& parameters,
-                     NativeStoneApplicationContext& context) :
+                     OrthancStone::NativeStoneApplicationContext& context) :
       BaseWebService(broker),
       oracle_(oracle),
       context_(context),
@@ -58,8 +58,8 @@
                            const HttpHeaders& headers,
                            const std::string& body,
                            Orthanc::IDynamicObject* payload, // takes ownership
-                           MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership
-                           MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL, // takes ownership
+                           OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership
+                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL, // takes ownership
                            unsigned int timeoutInSeconds = 60)
     {
       oracle_.Submit(new WebServicePostCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, body, payload, context_));
@@ -68,8 +68,8 @@
     virtual void DeleteAsync(const std::string& uri,
                              const HttpHeaders& headers,
                              Orthanc::IDynamicObject* payload,
-                             MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                             MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                             OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                             OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                              unsigned int timeoutInSeconds = 60)
     {
       oracle_.Submit(new WebServiceDeleteCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
@@ -79,8 +79,8 @@
     virtual void GetAsyncInternal(const std::string& uri,
                                   const HttpHeaders& headers,
                                   Orthanc::IDynamicObject* payload, // takes ownership
-                                  MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,   // takes ownership
-                                  MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,// takes ownership
+                                  OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,   // takes ownership
+                                  OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,// takes ownership
                                   unsigned int timeoutInSeconds = 60)
     {
       oracle_.Submit(new WebServiceGetCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
@@ -88,7 +88,7 @@
 
     virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
                                         Orthanc::IDynamicObject* payload, // takes ownership
-                                        MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback);
+                                        OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback);
 
   };
 }
--- a/Platforms/Generic/WebServiceCommandBase.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServiceCommandBase.cpp	Tue May 21 13:25:58 2019 +0200
@@ -23,17 +23,17 @@
 
 #include <Core/HttpClient.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  WebServiceCommandBase::WebServiceCommandBase(MessageBroker& broker,
-                                               MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                                               MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+  WebServiceCommandBase::WebServiceCommandBase(OrthancStone::MessageBroker& broker,
+                                               OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                                               OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
                                                const Orthanc::WebServiceParameters& parameters,
                                                const std::string& url,
                                                const IWebService::HttpHeaders& headers,
                                                unsigned int timeoutInSeconds,
                                                Orthanc::IDynamicObject* payload /* takes ownership */,
-                                               NativeStoneApplicationContext& context) :
+                                               OrthancStone::NativeStoneApplicationContext& context) :
     IObservable(broker),
     successCallback_(successCallback),
     failureCallback_(failureCallback),
@@ -52,7 +52,7 @@
     // We want to make sure that, i.e, the UpdateThread is not
     // triggered while we are updating the "model" with the result of
     // a WebServiceCommand
-    NativeStoneApplicationContext::GlobalMutexLocker lock(context_); 
+    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker lock(context_); 
 
     if (success_ && successCallback_.get() != NULL)
     {
--- a/Platforms/Generic/WebServiceCommandBase.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServiceCommandBase.h	Tue May 21 13:25:58 2019 +0200
@@ -32,13 +32,13 @@
 
 #include <memory>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  class WebServiceCommandBase : public IOracleCommand, IObservable
+  class WebServiceCommandBase : public IOracleCommand, OrthancStone::IObservable
   {
   protected:
-    std::auto_ptr<MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
-    std::auto_ptr<MessageHandler<IWebService::HttpRequestErrorMessage> >    failureCallback_;
+    std::auto_ptr<OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> >  successCallback_;
+    std::auto_ptr<OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >    failureCallback_;
     Orthanc::WebServiceParameters           parameters_;
     std::string                             url_;
     IWebService::HttpHeaders                headers_;
@@ -46,19 +46,19 @@
     bool                                    success_;
     std::string                             answer_;
     IWebService::HttpHeaders                answerHeaders_;
-    NativeStoneApplicationContext&          context_;
+    OrthancStone::NativeStoneApplicationContext&          context_;
     unsigned int                            timeoutInSeconds_;
 
   public:
-    WebServiceCommandBase(MessageBroker& broker,
-                          MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                          MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+    WebServiceCommandBase(OrthancStone::MessageBroker& broker,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                           const Orthanc::WebServiceParameters& parameters,
                           const std::string& url,
                           const IWebService::HttpHeaders& headers,
                           unsigned int timeoutInSeconds,
                           Orthanc::IDynamicObject* payload /* takes ownership */,
-                          NativeStoneApplicationContext& context
+                          OrthancStone::NativeStoneApplicationContext& context
                           );
 
     virtual void Execute() = 0;
--- a/Platforms/Generic/WebServiceDeleteCommand.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServiceDeleteCommand.cpp	Tue May 21 13:25:58 2019 +0200
@@ -23,17 +23,17 @@
 
 #include <Core/HttpClient.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  WebServiceDeleteCommand::WebServiceDeleteCommand(MessageBroker& broker,
-                                                   MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                                                   MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+  WebServiceDeleteCommand::WebServiceDeleteCommand(OrthancStone::MessageBroker& broker,
+                                                   OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                                                   OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                                                    const Orthanc::WebServiceParameters& parameters,
                                                    const std::string& url,
-                                                   const IWebService::HttpHeaders& headers,
+                                                   const Deprecated::IWebService::HttpHeaders& headers,
                                                    unsigned int timeoutInSeconds,
                                                    Orthanc::IDynamicObject* payload /* takes ownership */,
-                                                   NativeStoneApplicationContext& context) :
+                                                   OrthancStone::NativeStoneApplicationContext& context) :
     WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context)
   {
   }
@@ -45,7 +45,7 @@
     client.SetTimeout(timeoutInSeconds_);
     client.SetMethod(Orthanc::HttpMethod_Delete);
 
-    for (IWebService::HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); it++ )
+    for (Deprecated::IWebService::HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); it++ )
     {
       client.AddHeader(it->first, it->second);
     }
--- a/Platforms/Generic/WebServiceDeleteCommand.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServiceDeleteCommand.h	Tue May 21 13:25:58 2019 +0200
@@ -23,20 +23,20 @@
 
 #include "WebServiceCommandBase.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WebServiceDeleteCommand : public WebServiceCommandBase
   {
   public:
-    WebServiceDeleteCommand(MessageBroker& broker,
-                            MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                            MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+    WebServiceDeleteCommand(OrthancStone::MessageBroker& broker,
+                            OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                            OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                             const Orthanc::WebServiceParameters& parameters,
                             const std::string& url,
                             const IWebService::HttpHeaders& headers,
                             unsigned int timeoutInSeconds,
                             Orthanc::IDynamicObject* payload /* takes ownership */,
-                            NativeStoneApplicationContext& context);
+                            OrthancStone::NativeStoneApplicationContext& context);
 
     virtual void Execute();
   };
--- a/Platforms/Generic/WebServiceGetCommand.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServiceGetCommand.cpp	Tue May 21 13:25:58 2019 +0200
@@ -23,18 +23,18 @@
 
 #include <Core/HttpClient.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
 
-  WebServiceGetCommand::WebServiceGetCommand(MessageBroker& broker,
-                                             MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                                             MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+  WebServiceGetCommand::WebServiceGetCommand(OrthancStone::MessageBroker& broker,
+                                             OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                                             OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                                              const Orthanc::WebServiceParameters& parameters,
                                              const std::string& url,
                                              const IWebService::HttpHeaders& headers,
                                              unsigned int timeoutInSeconds,
                                              Orthanc::IDynamicObject* payload /* takes ownership */,
-                                             NativeStoneApplicationContext& context) :
+                                             OrthancStone::NativeStoneApplicationContext& context) :
     WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context)
   {
   }
--- a/Platforms/Generic/WebServiceGetCommand.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServiceGetCommand.h	Tue May 21 13:25:58 2019 +0200
@@ -23,20 +23,20 @@
 
 #include "WebServiceCommandBase.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WebServiceGetCommand : public WebServiceCommandBase
   {
   public:
-    WebServiceGetCommand(MessageBroker& broker,
-                         MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                         MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+    WebServiceGetCommand(OrthancStone::MessageBroker& broker,
+                         OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                         OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                          const Orthanc::WebServiceParameters& parameters,
                          const std::string& url,
                          const IWebService::HttpHeaders& headers,
                          unsigned int timeoutInSeconds,
                          Orthanc::IDynamicObject* payload /* takes ownership */,
-                         NativeStoneApplicationContext& context);
+                         OrthancStone::NativeStoneApplicationContext& context);
 
     virtual void Execute();
   };
--- a/Platforms/Generic/WebServicePostCommand.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServicePostCommand.cpp	Tue May 21 13:25:58 2019 +0200
@@ -23,18 +23,18 @@
 
 #include <Core/HttpClient.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
-  WebServicePostCommand::WebServicePostCommand(MessageBroker& broker,
-                                               MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                                               MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+  WebServicePostCommand::WebServicePostCommand(OrthancStone::MessageBroker& broker,
+                                               OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                                               OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                                                const Orthanc::WebServiceParameters& parameters,
                                                const std::string& url,
-                                               const IWebService::HttpHeaders& headers,
+                                               const Deprecated::IWebService::HttpHeaders& headers,
                                                unsigned int timeoutInSeconds,
                                                const std::string& body,
                                                Orthanc::IDynamicObject* payload /* takes ownership */,
-                                               NativeStoneApplicationContext& context) :
+                                               OrthancStone::NativeStoneApplicationContext& context) :
     WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context),
     body_(body)
   {
@@ -48,7 +48,7 @@
     client.SetMethod(Orthanc::HttpMethod_Post);
     client.GetBody().swap(body_);
 
-    for (IWebService::HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); it++ )
+    for (Deprecated::IWebService::HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); it++ )
     {
       client.AddHeader(it->first, it->second);
     }
--- a/Platforms/Generic/WebServicePostCommand.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Generic/WebServicePostCommand.h	Tue May 21 13:25:58 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "WebServiceCommandBase.h"
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WebServicePostCommand : public WebServiceCommandBase
   {
@@ -31,16 +31,16 @@
     std::string  body_;
 
   public:
-    WebServicePostCommand(MessageBroker& broker,
-                          MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
-                          MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
+    WebServicePostCommand(OrthancStone::MessageBroker& broker,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                           const Orthanc::WebServiceParameters& parameters,
                           const std::string& url,
                           const IWebService::HttpHeaders& headers,
                           unsigned int timeoutInSeconds,
                           const std::string& body,
                           Orthanc::IDynamicObject* payload /* takes ownership */,
-                          NativeStoneApplicationContext& context);
+                          OrthancStone::NativeStoneApplicationContext& context);
 
     virtual void Execute();
   };
--- a/Platforms/Wasm/Defaults.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/Defaults.cpp	Tue May 21 13:25:58 2019 +0200
@@ -26,16 +26,16 @@
 static OrthancStone::ViewportContentChangedObserver viewportContentChangedObserver_(broker);
 static OrthancStone::StatusBar statusBar_;
 
-static std::list<std::shared_ptr<OrthancStone::WidgetViewport>> viewports_;
+static std::list<std::shared_ptr<Deprecated::WidgetViewport>> viewports_;
 
-std::shared_ptr<OrthancStone::WidgetViewport> FindViewportSharedPtr(ViewportHandle viewport) {
+std::shared_ptr<Deprecated::WidgetViewport> FindViewportSharedPtr(ViewportHandle viewport) {
   for (const auto& v : viewports_) {
     if (v.get() == viewport) {
       return v;
     }
   }
   assert(false);
-  return std::shared_ptr<OrthancStone::WidgetViewport>();
+  return std::shared_ptr<Deprecated::WidgetViewport>();
 }
 
 #ifdef __cplusplus
@@ -47,7 +47,7 @@
   // when WASM needs a C++ viewport
   ViewportHandle EMSCRIPTEN_KEEPALIVE CreateCppViewport() {
     
-    std::shared_ptr<OrthancStone::WidgetViewport> viewport(new OrthancStone::WidgetViewport(broker));
+    std::shared_ptr<Deprecated::WidgetViewport> viewport(new Deprecated::WidgetViewport(broker));
     printf("viewport %x\n", (int)viewport.get());
 
     viewports_.push_back(viewport);
@@ -57,7 +57,7 @@
     viewport->SetStatusBar(statusBar_);
 
     viewport->RegisterObserverCallback(
-      new Callable<ViewportContentChangedObserver, IViewport::ViewportChangedMessage>
+      new Callable<ViewportContentChangedObserver, Deprecated::IViewport::ViewportChangedMessage>
       (viewportContentChangedObserver_, &ViewportContentChangedObserver::OnViewportChanged));
 
     return viewport.get();
@@ -65,7 +65,7 @@
 
   // when WASM does not need a viewport anymore, it should release it 
   void EMSCRIPTEN_KEEPALIVE ReleaseCppViewport(ViewportHandle viewport) {
-    viewports_.remove_if([viewport](const std::shared_ptr<OrthancStone::WidgetViewport>& v) { return v.get() == viewport;});
+    viewports_.remove_if([viewport](const std::shared_ptr<Deprecated::WidgetViewport>& v) { return v.get() == viewport;});
 
     printf("There are now %lu viewports in C++\n", viewports_.size());
   }
@@ -76,8 +76,8 @@
 
     application.reset(CreateUserApplication(broker));
     applicationWasmAdapter.reset(CreateWasmApplicationAdapter(broker, application.get())); 
-    WasmWebService::SetBroker(broker);
-    WasmDelayedCallExecutor::SetBroker(broker);
+    Deprecated::WasmWebService::SetBroker(broker);
+    Deprecated::WasmDelayedCallExecutor::SetBroker(broker);
 
     startupParametersBuilder.Clear();
   }
@@ -104,8 +104,8 @@
     context.reset(new OrthancStone::StoneApplicationContext(broker));
     context->SetOrthancBaseUrl(baseUri);
     printf("Base URL to Orthanc API: [%s]\n", baseUri);
-    context->SetWebService(OrthancStone::WasmWebService::GetInstance());
-    context->SetDelayedCallExecutor(OrthancStone::WasmDelayedCallExecutor::GetInstance());
+    context->SetWebService(Deprecated::WasmWebService::GetInstance());
+    context->SetDelayedCallExecutor(Deprecated::WasmDelayedCallExecutor::GetInstance());
     application->Initialize(context.get(), statusBar_, parameters);
     application->InitializeWasm();
 
@@ -208,7 +208,7 @@
         return;  // Unknown button
     }
 
-    viewport->MouseDown(button, x, y, OrthancStone::KeyboardModifiers_None, std::vector<OrthancStone::Touch>());
+    viewport->MouseDown(button, x, y, OrthancStone::KeyboardModifiers_None, std::vector<Deprecated::Touch>());
   }
   
 
@@ -239,10 +239,10 @@
                                               int x,
                                               int y)
   {
-    viewport->MouseMove(x, y, std::vector<OrthancStone::Touch>());
+    viewport->MouseMove(x, y, std::vector<Deprecated::Touch>());
   }
 
-  void GetTouchVector(std::vector<OrthancStone::Touch>& output,
+  void GetTouchVector(std::vector<Deprecated::Touch>& output,
                       int touchCount,
                       float x0,
                       float y0,
@@ -254,15 +254,15 @@
     // TODO: it might be nice to try to pass all the x0,y0 coordinates as arrays but that's not so easy to pass array between JS and C++
     if (touchCount > 0)
     {
-      output.push_back(OrthancStone::Touch(x0, y0));
+      output.push_back(Deprecated::Touch(x0, y0));
     }
     if (touchCount > 1)
     {
-      output.push_back(OrthancStone::Touch(x1, y1));
+      output.push_back(Deprecated::Touch(x1, y1));
     }
     if (touchCount > 2)
     {
-      output.push_back(OrthancStone::Touch(x2, y2));
+      output.push_back(Deprecated::Touch(x2, y2));
     }
 
   }
@@ -278,7 +278,7 @@
   {
     printf("touch start with %d touches\n", touchCount);
 
-    std::vector<OrthancStone::Touch> touches;
+    std::vector<Deprecated::Touch> touches;
     GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2);
     viewport->TouchStart(touches);
   }
@@ -294,7 +294,7 @@
   {
     printf("touch move with %d touches\n", touchCount);
 
-    std::vector<OrthancStone::Touch> touches;
+    std::vector<Deprecated::Touch> touches;
     GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2);
     viewport->TouchMove(touches);
   }
@@ -310,7 +310,7 @@
   {
     printf("touch end with %d touches remaining\n", touchCount);
 
-    std::vector<OrthancStone::Touch> touches;
+    std::vector<Deprecated::Touch> touches;
     GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2);
     viewport->TouchEnd(touches);
   }
--- a/Platforms/Wasm/Defaults.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/Defaults.h	Tue May 21 13:25:58 2019 +0200
@@ -8,7 +8,7 @@
 #include <Applications/IStoneApplication.h>
 #include <Platforms/Wasm/WasmPlatformApplicationAdapter.h>
 
-typedef OrthancStone::WidgetViewport* ViewportHandle; // the objects exchanged between JS and C++
+typedef Deprecated::WidgetViewport* ViewportHandle; // the objects exchanged between JS and C++
 
 #ifdef __cplusplus
 extern "C" {
@@ -57,7 +57,7 @@
       isScheduled_ = false;
     }
 
-    void OnViewportChanged(const IViewport::ViewportChangedMessage& message)
+    void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
     {
       if (!isScheduled_)
       {
@@ -68,7 +68,7 @@
   };
 
   // default status bar to log messages on the console/stdout
-  class StatusBar : public OrthancStone::IStatusBar
+  class StatusBar : public Deprecated::IStatusBar
   {
   public:
     virtual void ClearMessage()
--- a/Platforms/Wasm/WasmDelayedCallExecutor.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/WasmDelayedCallExecutor.cpp	Tue May 21 13:25:58 2019 +0200
@@ -21,8 +21,8 @@
     }
     else
     {
-      reinterpret_cast<OrthancStone::MessageHandler<OrthancStone::IDelayedCallExecutor::TimeoutMessage>*>(callable)->
-        Apply(OrthancStone::IDelayedCallExecutor::TimeoutMessage()); // uri, reinterpret_cast<Orthanc::IDynamicObject*>(payload)));
+      reinterpret_cast<OrthancStone::MessageHandler<Deprecated::IDelayedCallExecutor::TimeoutMessage>*>(callable)->
+        Apply(Deprecated::IDelayedCallExecutor::TimeoutMessage()); // uri, reinterpret_cast<Orthanc::IDynamicObject*>(payload)));
     }
   }
 
@@ -33,12 +33,12 @@
 
 
 
-namespace OrthancStone
+namespace Deprecated
 {
-  MessageBroker* WasmDelayedCallExecutor::broker_ = NULL;
+  OrthancStone::MessageBroker* WasmDelayedCallExecutor::broker_ = NULL;
 
 
-  void WasmDelayedCallExecutor::Schedule(MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
+  void WasmDelayedCallExecutor::Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
                          unsigned int timeoutInMs)
   {
     WasmDelayedCallExecutor_Schedule(callback, timeoutInMs);
--- a/Platforms/Wasm/WasmDelayedCallExecutor.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/WasmDelayedCallExecutor.h	Tue May 21 13:25:58 2019 +0200
@@ -3,15 +3,15 @@
 #include <Framework/Toolbox/IDelayedCallExecutor.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
   class WasmDelayedCallExecutor : public IDelayedCallExecutor
   {
   private:
-    static MessageBroker* broker_;
+    static OrthancStone::MessageBroker* broker_;
 
     // Private constructor => Singleton design pattern
-    WasmDelayedCallExecutor(MessageBroker& broker) :
+    WasmDelayedCallExecutor(OrthancStone::MessageBroker& broker) :
       IDelayedCallExecutor(broker)
     {
     }
@@ -28,12 +28,12 @@
       return instance;
     }
 
-    static void SetBroker(MessageBroker& broker)
+    static void SetBroker(OrthancStone::MessageBroker& broker)
     {
       broker_ = &broker;
     }
 
-    virtual void Schedule(MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
+    virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
                          unsigned int timeoutInMs = 1000);
 
   };
--- a/Platforms/Wasm/WasmViewport.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/WasmViewport.cpp	Tue May 21 13:25:58 2019 +0200
@@ -3,11 +3,11 @@
 #include <vector>
 #include <memory>
 
-std::vector<std::shared_ptr<OrthancStone::WidgetViewport>> wasmViewports;
+std::vector<std::shared_ptr<Deprecated::WidgetViewport>> wasmViewports;
 
-void AttachWidgetToWasmViewport(const char* htmlCanvasId, OrthancStone::IWidget* centralWidget) {
-    std::shared_ptr<OrthancStone::WidgetViewport> viewport(CreateWasmViewportFromCpp(htmlCanvasId));
+void AttachWidgetToWasmViewport(const char* htmlCanvasId, Deprecated::IWidget* centralWidget) {
+    std::shared_ptr<Deprecated::WidgetViewport> viewport(CreateWasmViewportFromCpp(htmlCanvasId));
     viewport->SetCentralWidget(centralWidget);
 
     wasmViewports.push_back(viewport);
-}
\ No newline at end of file
+}
--- a/Platforms/Wasm/WasmViewport.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/WasmViewport.h	Tue May 21 13:25:58 2019 +0200
@@ -9,10 +9,10 @@
 #endif
 
   // JS methods accessible from C++
-  extern OrthancStone::WidgetViewport* CreateWasmViewportFromCpp(const char* htmlCanvasId);
+  extern Deprecated::WidgetViewport* CreateWasmViewportFromCpp(const char* htmlCanvasId);
 
 #ifdef __cplusplus
 }
 #endif
 
-extern void AttachWidgetToWasmViewport(const char* htmlCanvasId, OrthancStone::IWidget* centralWidget);
+extern void AttachWidgetToWasmViewport(const char* htmlCanvasId, Deprecated::IWidget* centralWidget);
--- a/Platforms/Wasm/WasmWebService.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/WasmWebService.cpp	Tue May 21 13:25:58 2019 +0200
@@ -6,9 +6,9 @@
 
 struct CachedSuccessNotification
 {
-  boost::shared_ptr<OrthancStone::BaseWebService::CachedHttpRequestSuccessMessage>    cachedMessage;
+  boost::shared_ptr<Deprecated::BaseWebService::CachedHttpRequestSuccessMessage>    cachedMessage;
   std::auto_ptr<Orthanc::IDynamicObject>                                              payload;
-  OrthancStone::MessageHandler<OrthancStone::IWebService::HttpRequestSuccessMessage>* successCallback;
+  OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback;
 };
 
 
@@ -47,8 +47,8 @@
   {
     if (failureCallable != NULL)
     {
-      reinterpret_cast<OrthancStone::MessageHandler<OrthancStone::IWebService::HttpRequestErrorMessage>*>(failureCallable)->
-        Apply(OrthancStone::IWebService::HttpRequestErrorMessage(uri, reinterpret_cast<Orthanc::IDynamicObject*>(payload)));
+      reinterpret_cast<OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>*>(failureCallable)->
+        Apply(Deprecated::IWebService::HttpRequestErrorMessage(uri, reinterpret_cast<Orthanc::IDynamicObject*>(payload)));
     }
   }
 
@@ -57,7 +57,7 @@
     // notification has been allocated in C++ and passed to JS.  It must be deleted by this method
     std::auto_ptr<CachedSuccessNotification> notification(reinterpret_cast<CachedSuccessNotification*>(notification_));
 
-    notification->successCallback->Apply(OrthancStone::IWebService::HttpRequestSuccessMessage(
+    notification->successCallback->Apply(Deprecated::IWebService::HttpRequestSuccessMessage(
       notification->cachedMessage->GetUri(), 
       notification->cachedMessage->GetAnswer(),
       notification->cachedMessage->GetAnswerSize(),
@@ -75,13 +75,13 @@
   {
     if (successCallable != NULL)
     {
-      OrthancStone::IWebService::HttpHeaders headers;
+      Deprecated::IWebService::HttpHeaders headers;
 
       // TODO - Parse "answerHeaders"
       //printf("TODO: parse headers [%s]\n", answerHeaders);
       
-      reinterpret_cast<OrthancStone::MessageHandler<OrthancStone::IWebService::HttpRequestSuccessMessage>*>(successCallable)->
-        Apply(OrthancStone::IWebService::HttpRequestSuccessMessage(uri, body, bodySize, headers,
+      reinterpret_cast<OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>*>(successCallable)->
+        Apply(Deprecated::IWebService::HttpRequestSuccessMessage(uri, body, bodySize, headers,
                                                                    reinterpret_cast<Orthanc::IDynamicObject*>(payload)));
     }
   }
@@ -92,9 +92,9 @@
 
 
 
-namespace OrthancStone
+namespace Deprecated
 {
-  MessageBroker* WasmWebService::broker_ = NULL;
+  OrthancStone::MessageBroker* WasmWebService::broker_ = NULL;
 
   void ToJsonString(std::string& output, const IWebService::HttpHeaders& headers)
   {
@@ -116,8 +116,8 @@
                                  const HttpHeaders& headers,
                                  const std::string& body,
                                  Orthanc::IDynamicObject* payload,
-                                 MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallable,
-                                 MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallable,
+                                 OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallable,
+                                 OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallable,
                                  unsigned int timeoutInSeconds)
   {
     std::string headersInJsonString;
@@ -129,8 +129,8 @@
   void WasmWebService::DeleteAsync(const std::string& relativeUri,
                                    const HttpHeaders& headers,
                                    Orthanc::IDynamicObject* payload,
-                                   MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallable,
-                                   MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallable,
+                                   OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallable,
+                                   OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallable,
                                    unsigned int timeoutInSeconds)
   {
     std::string headersInJsonString;
@@ -142,8 +142,8 @@
   void WasmWebService::GetAsyncInternal(const std::string &relativeUri,
                                         const HttpHeaders &headers,
                                         Orthanc::IDynamicObject *payload,
-                                        MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
-                                        MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable,
+                                        OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
+                                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable,
                                         unsigned int timeoutInSeconds)
   {
     std::string headersInJsonString;
@@ -153,8 +153,8 @@
   }
 
   void WasmWebService::NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedMessage,
-                                                Orthanc::IDynamicObject* payload, // takes ownership
-                                                MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback)
+                                              Orthanc::IDynamicObject* payload, // takes ownership
+                                              OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback)
   {
     CachedSuccessNotification* notification = new CachedSuccessNotification();  // allocated on the heap, it will be passed to JS and deleted when coming back to C++
     notification->cachedMessage = cachedMessage;
--- a/Platforms/Wasm/WasmWebService.h	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/WasmWebService.h	Tue May 21 13:25:58 2019 +0200
@@ -3,15 +3,15 @@
 #include <Framework/Toolbox/BaseWebService.h>
 #include <Core/OrthancException.h>
 
-namespace OrthancStone
+namespace Deprecated
 {
 class WasmWebService : public BaseWebService
 {
 private:
-  static MessageBroker *broker_;
+  static OrthancStone::MessageBroker *broker_;
 
   // Private constructor => Singleton design pattern
-  WasmWebService(MessageBroker &broker) : BaseWebService(broker)
+  WasmWebService(OrthancStone::MessageBroker &broker) : BaseWebService(broker)
   {
   }
 
@@ -27,7 +27,7 @@
     return instance;
   }
 
-  static void SetBroker(MessageBroker &broker)
+  static void SetBroker(OrthancStone::MessageBroker &broker)
   {
     broker_ = &broker;
   }
@@ -36,27 +36,27 @@
                          const HttpHeaders &headers,
                          const std::string &body,
                          Orthanc::IDynamicObject *payload,
-                         MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
-                         MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable = NULL,
+                         OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
+                         OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable = NULL,
                          unsigned int timeoutInSeconds = 60);
 
   virtual void DeleteAsync(const std::string &uri,
                            const HttpHeaders &headers,
                            Orthanc::IDynamicObject *payload,
-                           MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
-                           MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable = NULL,
+                           OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
+                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable = NULL,
                            unsigned int timeoutInSeconds = 60);
 
 protected:
   virtual void GetAsyncInternal(const std::string &uri,
                                 const HttpHeaders &headers,
                                 Orthanc::IDynamicObject *payload,
-                                MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
-                                MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable = NULL,
+                                OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallable,
+                                OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> *failureCallable = NULL,
                                 unsigned int timeoutInSeconds = 60);
 
   virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
                                       Orthanc::IDynamicObject *payload, // takes ownership
-                                      MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallback);
+                                      OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> *successCallback);
 };
-} // namespace OrthancStone
+} // namespace Deprecated
--- a/Platforms/Wasm/wasm-application-runner.ts	Thu May 16 19:10:38 2019 +0200
+++ b/Platforms/Wasm/wasm-application-runner.ts	Tue May 21 13:25:58 2019 +0200
@@ -22,6 +22,15 @@
 var StartWasmApplication: Function = null;
 export var SendSerializedMessageToStoneApplication: Function = null;
 
+var auxiliaryParameters : Map<string,string>  = null;
+
+export function SetApplicationParameters(params : Map<string,string>) {
+  if (auxiliaryParameters != null) {
+    console.warn("wasm-application-runner.SetApplicationParameters: about to overwrite the existing application parameters!")
+  }
+  auxiliaryParameters = params;
+}
+
 function DoAnimationThread() {
   if (WasmDoAnimation != null) {
     WasmDoAnimation();
@@ -31,6 +40,7 @@
   setTimeout(DoAnimationThread, 100);  
 }
 
+
 function GetUriParameters(): Map<string, string> {
   var parameters = window.location.search.substr(1);
 
@@ -63,7 +73,16 @@
 
   CreateWasmApplication();
 
-  // parse uri and transmit the parameters to the app before initializing it
+  // transmit the API-specified parameters to the app before initializing it
+  for (let key in auxiliaryParameters) {
+    if (auxiliaryParameters.hasOwnProperty(key)) {
+      Logger.defaultLogger.debug(
+        `About to call SetStartupParameter("${key}","${auxiliaryParameters[key]}")`);
+      SetStartupParameter(key, auxiliaryParameters[key]);
+    }
+  }
+
+  // parse uri and transmit the URI parameters to the app before initializing it
   let parameters = GetUriParameters();
 
   for (let key in parameters) {
--- a/README.md	Thu May 16 19:10:38 2019 +0200
+++ b/README.md	Tue May 21 13:25:58 2019 +0200
@@ -241,17 +241,26 @@
 How to build the newest (2019-04-29) SDL samples under Windows, *inside* a
 folder that is sibling to the orthanc-stone folder: 
 
+**Visual Studio 2017 (v140) **
+
 ```
 cmake -G "Visual Studio 15 2017 Win64" -DMSVC_MULTIPLE_PROCESSES=ON -DENABLE_OPENGL=ON -DSTATIC_BUILD=ON -DOPENSSL_NO_CAPIENG=ON -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT="$($pwd)\..\orthanc" -DALLOW_DOWNLOADS=ON -DENABLE_SDL=ON ../orthanc-stone/Samples/Sdl
 ```
 
+**Visual Studio 2008 (v90) **
+
+```
+cmake -G "Visual Studio 9 2008" -DUSE_LEGACY_JSONCPP=ON -DENABLE_OPENGL=ON -DSTATIC_BUILD=ON -DOPENSSL_NO_CAPIENG=ON -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT="$($pwd)\..\orthanc" -DALLOW_DOWNLOADS=ON -DENABLE_SDL=ON ../orthanc-stone/Samples/Sdl
+```
+
 And under Ubuntu (note the /mnt/c/osi/dev/orthanc folder):
 ```
 cmake -G "Ninja" -DENABLE_OPENGL=ON -DSTATIC_BUILD=OFF -DOPENSSL_NO_CAPIENG=ON -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT="/mnt/c/osi/dev/orthanc" -DALLOW_DOWNLOADS=ON -DENABLE_SDL=ON ../orthanc-stone/Samples/Sdl
 ```
 
 TODO trackers:
-- text overlay 50% --> ColorTextureLayer 50%
-- angle tracker: draw arcs
+- CANCELLED (using outlined text now) text overlay 50% --> ColorTextureLayer 50%
+- DONE angle tracker: draw arcs
+- Handles on arc
+- Select measure tool with hit test --> Delete command
 
-
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Thu May 16 19:10:38 2019 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue May 21 13:25:58 2019 +0200
@@ -329,6 +329,40 @@
   ${ORTHANC_STONE_ROOT}/Framework/Scene2D/TextureBaseSceneLayer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Scene2D/ZoomSceneTracker.cpp
 
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/AngleMeasureTool.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/AngleMeasureTool.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateAngleMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateCircleMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateCircleMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateLineMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/CreateSimpleTrackerAdapter.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditAngleMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditCircleMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditCircleMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditLineMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/EditLineMeasureTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/IFlexiblePointerTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/LineMeasureTool.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/LineMeasureTool.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureCommands.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureCommands.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureTools.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureTools.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureToolsToolbox.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureToolsToolbox.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureTrackers.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/MeasureTrackers.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/OneGesturePointerTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/OneGesturePointerTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/PointerTypes.h
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/ViewportController.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/ViewportController.h
+
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/FontRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/Glyph.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphAlphabet.cpp
@@ -346,6 +380,8 @@
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/RenderStyle.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/SliceOutlineRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Loaders/BasicFetchingItemsSorter.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Loaders/BasicFetchingStrategy.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyAlphaLayer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyDicomLayer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayer.cpp
@@ -391,6 +427,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ViewportGeometry.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/VolumeImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoContext.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoSurface.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/IMouseTracker.h
--- a/Samples/Common/AngleMeasureTool.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "AngleMeasureTool.h"
-#include "MeasureToolsToolbox.h"
-
-#include <Core/Logging.h>
-
-#include <boost/math/constants/constants.hpp>
-
-extern void TrackerSample_SetInfoDisplayMessage(std::string key, std::string value);
-
-namespace OrthancStone
-{
-  AngleMeasureTool::~AngleMeasureTool()
-  {
-    // this measuring tool is a RABI for the corresponding visual layers
-    // stored in the 2D scene
-    Disable();
-    RemoveFromScene();
-  }
-
-  void AngleMeasureTool::RemoveFromScene()
-  {
-    if (layersCreated)
-    {
-      assert(GetScene().HasLayer(polylineZIndex_));
-      assert(GetScene().HasLayer(textZIndex_));
-      GetScene().DeleteLayer(polylineZIndex_);
-      GetScene().DeleteLayer(textZIndex_);
-    }
-  }
-
-  void AngleMeasureTool::SetSide1End(ScenePoint2D pt)
-  {
-    side1End_ = pt;
-    RefreshScene();
-  }
-
-  void AngleMeasureTool::SetSide2End(ScenePoint2D pt)
-  {
-    side2End_ = pt;
-    RefreshScene();
-  }
-
-  void AngleMeasureTool::SetCenter(ScenePoint2D pt)
-  {
-    center_ = pt;
-    RefreshScene();
-  }
-  
-  PolylineSceneLayer* AngleMeasureTool::GetPolylineLayer()
-  {
-    assert(GetScene().HasLayer(polylineZIndex_));
-    ISceneLayer* layer = &(GetScene().GetLayer(polylineZIndex_));
-    PolylineSceneLayer* concreteLayer = dynamic_cast<PolylineSceneLayer*>(layer);
-    assert(concreteLayer != NULL);
-    return concreteLayer;
-  }
-
-  TextSceneLayer* AngleMeasureTool::GetTextLayer()
-  {
-    assert(GetScene().HasLayer(textZIndex_));
-    ISceneLayer* layer = &(GetScene().GetLayer(textZIndex_));
-    TextSceneLayer* concreteLayer = dynamic_cast<TextSceneLayer*>(layer);
-    assert(concreteLayer != NULL);
-    return concreteLayer;
-  }
-
-
-  void AngleMeasureTool::RefreshScene()
-  {
-    if (IsEnabled())
-    {
-      // get the scaling factor 
-      const double pixelToScene =
-        GetScene().GetCanvasToSceneTransform().ComputeZoom();
-
-      if (!layersCreated)
-      {
-        // Create the layers if need be
-
-        assert(textZIndex_ == -1);
-        {
-          polylineZIndex_ = GetScene().GetMaxDepth() + 100;
-          //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
-          std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
-          GetScene().SetLayer(polylineZIndex_, layer.release());
-        }
-        {
-          textZIndex_ = GetScene().GetMaxDepth() + 100;
-          //LOG(INFO) << "set textZIndex_ to: " << textZIndex_;
-          std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-          GetScene().SetLayer(textZIndex_, layer.release());
-        }
-        layersCreated = true;
-      }
-      else
-      {
-        assert(GetScene().HasLayer(polylineZIndex_));
-        assert(GetScene().HasLayer(textZIndex_));
-      }
-      {
-        // Fill the polyline layer with the measurement line
-
-        PolylineSceneLayer* polylineLayer = GetPolylineLayer();
-        polylineLayer->ClearAllChains();
-        polylineLayer->SetColor(0, 223, 21);
-
-        // sides
-        {
-          {
-            PolylineSceneLayer::Chain chain;
-            chain.push_back(side1End_);
-            chain.push_back(center_);
-            polylineLayer->AddChain(chain, false);
-          }
-          {
-            PolylineSceneLayer::Chain chain;
-            chain.push_back(side2End_);
-            chain.push_back(center_);
-            polylineLayer->AddChain(chain, false);
-          }
-        }
-
-        // handles
-        {
-          //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
-
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, GetScene(), side1End_, 10.0* pixelToScene); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
-
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, GetScene(), side2End_, 10.0* pixelToScene); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
-        }
-
-        // arc
-        {
-          PolylineSceneLayer::Chain chain;
-
-          const double ARC_RADIUS_CANVAS_COORD = 30.0;
-          AddShortestArc(chain, GetScene(), side1End_, center_, side2End_, 
-            ARC_RADIUS_CANVAS_COORD*pixelToScene);
-          polylineLayer->AddChain(chain, false);
-        }
-      }
-      {
-        // Set the text layer
-
-        double p1cAngle = atan2(
-          side1End_.GetY() - center_.GetY(),
-          side1End_.GetX() - center_.GetX());
-
-        TrackerSample_SetInfoDisplayMessage("center_.GetX()",
-          boost::lexical_cast<std::string>(center_.GetX()));
-
-        TrackerSample_SetInfoDisplayMessage("center_.GetY()",
-          boost::lexical_cast<std::string>(center_.GetY()));
-
-        TrackerSample_SetInfoDisplayMessage("side1End_.GetX()",
-          boost::lexical_cast<std::string>(side1End_.GetX()));
-
-        TrackerSample_SetInfoDisplayMessage("side1End_.GetY()",
-          boost::lexical_cast<std::string>(side1End_.GetY()));
-
-        TrackerSample_SetInfoDisplayMessage("side2End_.GetX()",
-          boost::lexical_cast<std::string>(side2End_.GetX()));
-
-        TrackerSample_SetInfoDisplayMessage("side2End_.GetY()",
-          boost::lexical_cast<std::string>(side2End_.GetY()));
-
-        TrackerSample_SetInfoDisplayMessage("p1cAngle (deg)",
-          boost::lexical_cast<std::string>(RadiansToDegrees(p1cAngle)));
-
-        double p2cAngle = atan2(
-          side2End_.GetY() - center_.GetY(),
-          side2End_.GetX() - center_.GetX());
-
-        double delta = NormalizeAngle(p2cAngle - p1cAngle);
-        TrackerSample_SetInfoDisplayMessage("delta (deg)",
-          boost::lexical_cast<std::string>(RadiansToDegrees(delta)));
-
-        double theta = p1cAngle + delta/2;
-
-        TrackerSample_SetInfoDisplayMessage("theta (deg)",
-          boost::lexical_cast<std::string>(RadiansToDegrees(theta)));
-
-        TrackerSample_SetInfoDisplayMessage("p2cAngle (deg)",
-          boost::lexical_cast<std::string>(RadiansToDegrees(p2cAngle)));
-
-        const double TEXT_CENTER_DISTANCE_CANVAS_COORD = 90;
-
-        double offsetX = TEXT_CENTER_DISTANCE_CANVAS_COORD * cos(theta);
-        TrackerSample_SetInfoDisplayMessage("offsetX (pix)",
-          boost::lexical_cast<std::string>(offsetX));
-
-        double offsetY = TEXT_CENTER_DISTANCE_CANVAS_COORD * sin(theta);
-        TrackerSample_SetInfoDisplayMessage("offsetY (pix)",
-          boost::lexical_cast<std::string>(offsetY));
-
-        double pointX = center_.GetX() + offsetX * pixelToScene;
-        double pointY = center_.GetY() + offsetY * pixelToScene;
-        TrackerSample_SetInfoDisplayMessage("pointX",
-          boost::lexical_cast<std::string>(pointX));
-
-        TrackerSample_SetInfoDisplayMessage("pointY",
-          boost::lexical_cast<std::string>(pointY));
-
-        TextSceneLayer* textLayer = GetTextLayer();
-
-        char buf[64];
-        double angleDeg = RadiansToDegrees(delta);
-
-        TrackerSample_SetInfoDisplayMessage("angleDeg",
-          boost::lexical_cast<std::string>(angleDeg));
-
-        sprintf(buf, "%0.02f deg", angleDeg);
-        textLayer->SetText(buf);
-        textLayer->SetColor(0, 223, 21);
-
-        ScenePoint2D textAnchor;
-        //GetPositionOnBisectingLine(
-        //  textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene);
-        textLayer->SetPosition(pointX, pointY);
-      }
-    }
-    else
-    {
-      if (layersCreated)
-      {
-        RemoveFromScene();
-        layersCreated = false;
-      }
-    }
-  }
-
-
-}
--- a/Samples/Common/AngleMeasureTool.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureTools.h"
-
-#include <Framework/Scene2D/Scene2D.h>
-#include <Framework/Scene2D/ScenePoint2D.h>
-#include <Framework/Scene2D/PolylineSceneLayer.h>
-#include <Framework/Scene2D/TextSceneLayer.h>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-#include <vector>
-#include <cmath>
-
-namespace OrthancStone
-{
-  class AngleMeasureTool : public MeasureTool
-  {
-  public:
-    AngleMeasureTool(MessageBroker& broker, Scene2D& scene)
-      : MeasureTool(broker, scene)
-      , layersCreated(false)
-      , polylineZIndex_(-1)
-      , textZIndex_(-1)
-    {
-
-    }
-
-    ~AngleMeasureTool();
-
-    void SetSide1End(ScenePoint2D start);
-    void SetCenter(ScenePoint2D start);
-    void SetSide2End(ScenePoint2D start);
-
-  private:
-    PolylineSceneLayer* GetPolylineLayer();
-    TextSceneLayer*     GetTextLayer();
-    virtual void        RefreshScene() ORTHANC_OVERRIDE;
-    void                RemoveFromScene();
-
-  private:
-    ScenePoint2D side1End_;
-    ScenePoint2D side2End_;
-    ScenePoint2D center_;
-    bool         layersCreated;
-    int          polylineZIndex_;
-    int          textZIndex_;
-  };
-
-  typedef boost::shared_ptr<AngleMeasureTool> AngleMeasureToolPtr;
-}
-
-
--- a/Samples/Common/CreateAngleMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CreateAngleMeasureTracker.h"
-#include <Core/OrthancException.h>
-
-using namespace Orthanc;
-
-namespace OrthancStone
-{
-  CreateAngleMeasureTracker::CreateAngleMeasureTracker(
-    MessageBroker&                  broker,
-    Scene2D&                        scene,
-    std::vector<TrackerCommandPtr>& undoStack,
-    std::vector<MeasureToolPtr>&    measureTools,
-    const PointerEvent&             e)
-    : CreateMeasureTracker(scene, undoStack, measureTools)
-    , state_(CreatingSide1)
-  {
-    command_.reset(
-      new CreateAngleMeasureCommand(
-        broker,
-        scene,
-        measureTools,
-        e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform())));
-  }
-
-  CreateAngleMeasureTracker::~CreateAngleMeasureTracker()
-  {
-  }
-
-  void CreateAngleMeasureTracker::PointerMove(const PointerEvent& event)
-  {
-    if (!active_)
-    {
-      throw OrthancException(ErrorCode_InternalError,
-        "Internal error: wrong state in CreateAngleMeasureTracker::"
-        "PointerMove: active_ == false");
-    }
-
-    ScenePoint2D scenePos = event.GetMainPosition().Apply(
-      scene_.GetCanvasToSceneTransform());
-
-    switch (state_)
-    {
-    case CreatingSide1:
-      GetCommand()->SetCenter(scenePos);
-      break;
-    case CreatingSide2:
-      GetCommand()->SetSide2End(scenePos);
-      break;
-    default:
-      throw OrthancException(ErrorCode_InternalError,
-        "Wrong state in CreateAngleMeasureTracker::"
-        "PointerMove: state_ invalid");
-    }
-    //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
-    //  "scenePos.GetY() = " << scenePos.GetY();
-  }
-
-  void CreateAngleMeasureTracker::PointerUp(const PointerEvent& e)
-  {
-    // TODO: the current app does not prevent multiple PointerDown AND
-    // PointerUp to be sent to the tracker.
-    // Unless we augment the PointerEvent structure with the button index, 
-    // we cannot really tell if this pointer up event matches the initial
-    // pointer down event. Let's make it simple for now.
-
-    switch (state_)
-    {
-    case CreatingSide1:
-      state_ = CreatingSide2;
-      break;
-    case CreatingSide2:
-      throw OrthancException(ErrorCode_InternalError,
-        "Wrong state in CreateAngleMeasureTracker::"
-        "PointerUp: state_ == CreatingSide2 ; this should not happen");
-      break;
-    default:
-      throw OrthancException(ErrorCode_InternalError,
-        "Wrong state in CreateAngleMeasureTracker::"
-        "PointerMove: state_ invalid");
-    }
-  }
-
-  void CreateAngleMeasureTracker::PointerDown(const PointerEvent& e)
-  {
-    switch (state_)
-    {
-    case CreatingSide1:
-      throw OrthancException(ErrorCode_InternalError,
-        "Wrong state in CreateAngleMeasureTracker::"
-        "PointerDown: state_ == CreatingSide1 ; this should not happen");
-      break;
-    case CreatingSide2:
-      // we are done
-      active_ = false;
-      break;
-    default:
-      throw OrthancException(ErrorCode_InternalError,
-        "Wrong state in CreateAngleMeasureTracker::"
-        "PointerMove: state_ invalid");
-    }
-  }
-
-  CreateAngleMeasureCommandPtr CreateAngleMeasureTracker::GetCommand()
-  {
-    return boost::dynamic_pointer_cast<CreateAngleMeasureCommand>(command_);
-  }
-
-}
--- a/Samples/Common/CreateAngleMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureTrackers.h"
-#include "MeasureCommands.h"
-
-#include <vector>
-
-namespace OrthancStone
-{
-  class CreateAngleMeasureTracker : public CreateMeasureTracker
-  {
-  public:
-    /**
-    When you create this tracker, you need to supply it with the undo stack
-    where it will store the commands that perform the actual measure tool
-    creation and modification.
-    In turn, a container for these commands to store the actual measuring
-    must be supplied, too
-    */
-    CreateAngleMeasureTracker(
-      MessageBroker&                  broker,
-      Scene2D&                        scene,
-      std::vector<TrackerCommandPtr>& undoStack,
-      std::vector<MeasureToolPtr>&    measureTools,
-      const PointerEvent&             e);
-
-    ~CreateAngleMeasureTracker();
-
-    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
-
-  private:
-    CreateAngleMeasureCommandPtr GetCommand();
-
-    enum State
-    {
-      CreatingSide1,
-      CreatingSide2,
-      Finished // just for debug
-    };
-    State state_;
-
-  };
-}
--- a/Samples/Common/CreateCircleMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/CreateCircleMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/CreateLineMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CreateLineMeasureTracker.h"
-#include <Core/OrthancException.h>
-
-using namespace Orthanc;
-
-namespace OrthancStone
-{
-  CreateLineMeasureTracker::CreateLineMeasureTracker(
-    MessageBroker&                  broker,
-    Scene2D&                        scene,
-    std::vector<TrackerCommandPtr>& undoStack,
-    std::vector<MeasureToolPtr>&    measureTools,
-    const PointerEvent&             e)
-    : CreateMeasureTracker(scene, undoStack, measureTools)
-  {
-    command_.reset(
-      new CreateLineMeasureCommand(
-        broker,
-        scene,
-        measureTools,
-        e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform())));
-  }
-
-  CreateLineMeasureTracker::~CreateLineMeasureTracker()
-  {
-
-  }
-
-  void CreateLineMeasureTracker::PointerMove(const PointerEvent& event)
-  {
-    if (!active_)
-    {
-      throw OrthancException(ErrorCode_InternalError,
-        "Internal error: wrong state in CreateLineMeasureTracker::"
-        "PointerMove: active_ == false");
-    }
-
-    ScenePoint2D scenePos = event.GetMainPosition().Apply(
-      scene_.GetCanvasToSceneTransform());
-
-    //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
-    //  "scenePos.GetY() = " << scenePos.GetY();
-
-    CreateLineMeasureTracker* concreteThis =
-      dynamic_cast<CreateLineMeasureTracker*>(this);
-    assert(concreteThis != NULL);
-    GetCommand()->SetEnd(scenePos);
-  }
-
-  void CreateLineMeasureTracker::PointerUp(const PointerEvent& e)
-  {
-    // TODO: the current app does not prevent multiple PointerDown AND
-    // PointerUp to be sent to the tracker.
-    // Unless we augment the PointerEvent structure with the button index, 
-    // we cannot really tell if this pointer up event matches the initial
-    // pointer down event. Let's make it simple for now.
-    active_ = false;
-  }
-
-  void CreateLineMeasureTracker::PointerDown(const PointerEvent& e)
-  {
-    LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) "
-      "are ignored when the line measure creation tracker is active";
-  }
-
-  CreateLineMeasureCommandPtr CreateLineMeasureTracker::GetCommand()
-  {
-    return boost::dynamic_pointer_cast<CreateLineMeasureCommand>(command_);
-  }
-
-}
--- a/Samples/Common/CreateLineMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureTrackers.h"
-
-namespace OrthancStone
-{
-  class CreateLineMeasureTracker : public CreateMeasureTracker
-  {
-  public:
-    /**
-    When you create this tracker, you need to supply it with the undo stack
-    where it will store the commands that perform the actual measure tool
-    creation and modification.
-    In turn, a container for these commands to store the actual measuring
-    must be supplied, too
-    */
-    CreateLineMeasureTracker(
-      MessageBroker&                  broker,
-      Scene2D&                        scene,
-      std::vector<TrackerCommandPtr>& undoStack,
-      std::vector<MeasureToolPtr>&    measureTools,
-      const PointerEvent&             e);
-
-    ~CreateLineMeasureTracker();
-
-    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
-
-  private:
-    CreateLineMeasureCommandPtr GetCommand();
-  };
-}
--- a/Samples/Common/CreateMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
--- a/Samples/Common/CreateMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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
-
--- a/Samples/Common/CreateSimpleTrackerAdapter.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IFlexiblePointerTracker.h"
-#include <Framework/Scene2D/IPointerTracker.h>
-
-
-namespace OrthancStone
-{
-  namespace 
-  {
-    class SimpleTrackerAdapter : public IFlexiblePointerTracker
-    {
-    public:
-      SimpleTrackerAdapter(PointerTrackerPtr wrappedTracker)
-        : wrappedTracker_(wrappedTracker)
-        , active_(true)
-      {
-      }
-
-      virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE
-      {
-        if(active_)
-          wrappedTracker_->Update(event);
-      };
-      virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE
-      {
-        if (wrappedTracker_)
-        {
-          wrappedTracker_->Release();
-          wrappedTracker_ = NULL;
-        }
-        active_ = false;
-      }
-      virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE
-      {
-        // nothing to do atm
-      }
-      virtual bool IsActive() const ORTHANC_OVERRIDE
-      {
-        return active_;
-      }
-
-      virtual void Cancel() ORTHANC_OVERRIDE
-      {
-        wrappedTracker_ = NULL;
-        active_ = false;
-      }
-
-    private:
-      PointerTrackerPtr wrappedTracker_;
-      bool active_;
-    };
-  }
-
-  FlexiblePointerTrackerPtr CreateSimpleTrackerAdapter(PointerTrackerPtr t)
-  {
-    return FlexiblePointerTrackerPtr(new SimpleTrackerAdapter(t));
-  }
-}
--- a/Samples/Common/EditAngleMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/EditAngleMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/EditCircleMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/EditCircleMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/EditLineMeasureTracker.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/EditLineMeasureTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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
-
-namespace OrthancStone
-{
-}
--- a/Samples/Common/IFlexiblePointerTracker.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 <Framework/Scene2D/PointerEvent.h>
-#include <boost/shared_ptr.hpp>
-
-namespace OrthancStone
-{
-  class IPointerTracker;
-  typedef boost::shared_ptr<IPointerTracker> PointerTrackerPtr;
-
-  /**
-  This interface represents a flexible mouse tracker that can respond to 
-  several events and is not automatically deleted upon mouse up or when touch
-  interaction is suspended : for instance, a stateful tracker with a two-step 
-  interaction like: click & drag --> mouse up --> drag --> mouse click 
-  (for instance, for an angle measuring tracker or an ellipse tracker)
-  */
-  class IFlexiblePointerTracker : public boost::noncopyable
-  {
-  public:
-    virtual ~IFlexiblePointerTracker() {}
-
-    /**
-    This method will be repeatedly called during user interaction
-    */
-    virtual void PointerMove(const PointerEvent& event) = 0;
-
-    /**
-    This method will be called when a touch/pointer is removed (mouse up, 
-    pen lift, finger removed...)
-    */
-    virtual void PointerUp(const PointerEvent& event) = 0;
-
-    /**
-    This method will be called when a touch/pointer is added (mouse down, 
-    pen or finger press)
-    */
-    virtual void PointerDown(const PointerEvent& event) = 0;
-
-    /**
-    This method will be repeatedly called by the tracker owner (for instance,
-    the application) to check whether the tracker must keep on receiving 
-    interaction or if its job is done and it should be deleted.
-    */
-    virtual bool IsActive() const = 0;
-
-    /**
-    This will be called if the tracker needs to be dismissed without committing
-    its changes to the underlying model. If the model has been modified during
-    tracker lifetime, it must be restored to its initial value
-    */
-    virtual void Cancel() = 0;
-  };
-
-  typedef boost::shared_ptr<IFlexiblePointerTracker> FlexiblePointerTrackerPtr;
-
-  /**
-  This factory adopts the supplied simple tracker and creates a flexible 
-  tracker wrapper around it.
-  */
-  FlexiblePointerTrackerPtr CreateSimpleTrackerAdapter(PointerTrackerPtr);
-}
-
--- a/Samples/Common/LineMeasureTool.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "LineMeasureTool.h"
-#include "MeasureToolsToolbox.h"
-
-#include <Core/Logging.h>
-
-
-namespace OrthancStone
-{
-  LineMeasureTool::~LineMeasureTool()
-  {
-    // this measuring tool is a RABI for the corresponding visual layers
-    // stored in the 2D scene
-    Disable();
-    RemoveFromScene();
-  }
-
-  void LineMeasureTool::RemoveFromScene()
-  {
-    if (layersCreated)
-    {
-      assert(GetScene().HasLayer(polylineZIndex_));
-      assert(GetScene().HasLayer(textZIndex_));
-      GetScene().DeleteLayer(polylineZIndex_);
-      GetScene().DeleteLayer(textZIndex_);
-    }
-  }
-
-
-  void LineMeasureTool::SetStart(ScenePoint2D start)
-  {
-    start_ = start;
-    RefreshScene();
-  }
-
-  void LineMeasureTool::SetEnd(ScenePoint2D end)
-  {
-    end_ = end;
-    RefreshScene();
-  }
-
-  void LineMeasureTool::Set(ScenePoint2D start, ScenePoint2D end)
-  {
-    start_ = start;
-    end_ = end;
-    RefreshScene();
-  }
-
-  PolylineSceneLayer* LineMeasureTool::GetPolylineLayer()
-  {
-    assert(GetScene().HasLayer(polylineZIndex_));
-    ISceneLayer* layer = &(GetScene().GetLayer(polylineZIndex_));
-    PolylineSceneLayer* concreteLayer = dynamic_cast<PolylineSceneLayer*>(layer);
-    assert(concreteLayer != NULL);
-    return concreteLayer;
-  }
-
-  TextSceneLayer* LineMeasureTool::GetTextLayer()
-  {
-    assert(GetScene().HasLayer(textZIndex_));
-    ISceneLayer* layer = &(GetScene().GetLayer(textZIndex_));
-    TextSceneLayer* concreteLayer = dynamic_cast<TextSceneLayer*>(layer);
-    assert(concreteLayer != NULL);
-    return concreteLayer;
-  }
-
-  void LineMeasureTool::RefreshScene()
-  {
-    if (IsEnabled())
-    {
-      if (!layersCreated)
-      {
-        // Create the layers if need be
-
-        assert(textZIndex_ == -1);
-        {
-          polylineZIndex_ = GetScene().GetMaxDepth() + 100;
-          //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
-          std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
-          GetScene().SetLayer(polylineZIndex_, layer.release());
-        }
-        {
-          textZIndex_ = GetScene().GetMaxDepth() + 100;
-          //LOG(INFO) << "set textZIndex_ to: " << textZIndex_;
-          std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-          GetScene().SetLayer(textZIndex_, layer.release());
-        }
-        layersCreated = true;
-      }
-      else
-      {
-        assert(GetScene().HasLayer(polylineZIndex_));
-        assert(GetScene().HasLayer(textZIndex_));
-      }
-      {
-        // Fill the polyline layer with the measurement line
-
-        PolylineSceneLayer* polylineLayer = GetPolylineLayer();
-        polylineLayer->ClearAllChains();
-        polylineLayer->SetColor(0, 223, 21);
-
-        {
-          PolylineSceneLayer::Chain chain;
-          chain.push_back(start_);
-          chain.push_back(end_);
-          polylineLayer->AddChain(chain, false);
-        }
-
-        // handles
-        {
-          //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
-
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, GetScene(), start_, 10.0); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
-
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, GetScene(), end_, 10.0); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
-
-          //ScenePoint2D startC = start_.Apply(GetScene().GetSceneToCanvasTransform());
-          //double squareSize = 10.0; 
-          //double startHandleLX = startC.GetX() - squareSize/2;
-          //double startHandleTY = startC.GetY() - squareSize / 2;
-          //double startHandleRX = startC.GetX() + squareSize / 2;
-          //double startHandleBY = startC.GetY() + squareSize / 2;
-          //ScenePoint2D startLTC(startHandleLX, startHandleTY);
-          //ScenePoint2D startRTC(startHandleRX, startHandleTY);
-          //ScenePoint2D startRBC(startHandleRX, startHandleBY);
-          //ScenePoint2D startLBC(startHandleLX, startHandleBY);
-
-          //ScenePoint2D startLT = startLTC.Apply(GetScene().GetCanvasToSceneTransform());
-          //ScenePoint2D startRT = startRTC.Apply(GetScene().GetCanvasToSceneTransform());
-          //ScenePoint2D startRB = startRBC.Apply(GetScene().GetCanvasToSceneTransform());
-          //ScenePoint2D startLB = startLBC.Apply(GetScene().GetCanvasToSceneTransform());
-
-          //PolylineSceneLayer::Chain chain;
-          //chain.push_back(startLT);
-          //chain.push_back(startRT);
-          //chain.push_back(startRB);
-          //chain.push_back(startLB);
-          //polylineLayer->AddChain(chain, true);
-        }
-
-      }
-      {
-        // Set the text layer proporeties
-
-        TextSceneLayer* textLayer = GetTextLayer();
-        double deltaX = end_.GetX() - start_.GetX();
-        double deltaY = end_.GetY() - start_.GetY();
-        double squareDist = deltaX * deltaX + deltaY * deltaY;
-        double dist = sqrt(squareDist);
-        char buf[64];
-        sprintf(buf, "%0.02f units", dist);
-        textLayer->SetText(buf);
-        textLayer->SetColor(0, 223, 21);
-
-        // TODO: for now we simply position the text overlay at the middle
-        // of the measuring segment
-        double midX = 0.5*(end_.GetX() + start_.GetX());
-        double midY = 0.5*(end_.GetY() + start_.GetY());
-        textLayer->SetPosition(midX, midY);
-      }
-    }
-    else
-    {
-      if (layersCreated)
-      {
-        RemoveFromScene();
-        layersCreated = false;
-      }
-    }
-  }
-
-
-}
\ No newline at end of file
--- a/Samples/Common/LineMeasureTool.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureTools.h"
-
-#include <Framework/Scene2D/Scene2D.h>
-#include <Framework/Scene2D/ScenePoint2D.h>
-#include <Framework/Scene2D/PolylineSceneLayer.h>
-#include <Framework/Scene2D/TextSceneLayer.h>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-#include <vector>
-#include <cmath>
-
-namespace OrthancStone
-{
-  class LineMeasureTool : public MeasureTool
-  {
-  public:
-    LineMeasureTool(MessageBroker& broker, Scene2D& scene)
-      : MeasureTool(broker, scene)
-      , layersCreated(false)
-      , polylineZIndex_(-1)
-      , textZIndex_(-1)
-    {
-
-    }
-
-    ~LineMeasureTool();
-
-    void SetStart(ScenePoint2D start);
-    void SetEnd(ScenePoint2D end);
-    void Set(ScenePoint2D start, ScenePoint2D end);
-
-  private:
-    PolylineSceneLayer* GetPolylineLayer();
-    TextSceneLayer*     GetTextLayer();
-    virtual void        RefreshScene() ORTHANC_OVERRIDE;
-    void                RemoveFromScene();
-
-  private:
-    ScenePoint2D start_;
-    ScenePoint2D end_;
-    bool         layersCreated;
-    int          polylineZIndex_;
-    int          textZIndex_;
-  };
-
-  typedef boost::shared_ptr<LineMeasureTool> LineMeasureToolPtr;
-}
-
--- a/Samples/Common/MeasureCommands.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureCommands.h"
-
-namespace OrthancStone
-{
-  void CreateMeasureCommand::Undo()
-  {
-    // simply disable the measure tool upon undo
-    GetMeasureTool()->Disable();
-  }
-
-  void CreateMeasureCommand::Redo()
-  {
-    GetMeasureTool()->Enable();
-  }
-
-  CreateMeasureCommand::CreateMeasureCommand(
-    Scene2D& scene, MeasureToolList& measureTools)
-    : TrackerCommand(scene)
-    , measureTools_(measureTools)
-  {
-
-  }
-
-  CreateMeasureCommand::~CreateMeasureCommand()
-  {
-    // deleting the command should not change the model state
-    // we thus leave it as is
-  }
-
-  CreateLineMeasureCommand::CreateLineMeasureCommand(
-    MessageBroker&    broker, 
-    Scene2D&          scene, 
-    MeasureToolList&  measureTools, 
-    ScenePoint2D      point)
-    : CreateMeasureCommand(scene, measureTools)
-    , measureTool_(new LineMeasureTool(broker,scene))
-  {
-    measureTools_.push_back(measureTool_);
-    measureTool_->Set(point, point);
-  }
-
-  void CreateLineMeasureCommand::SetEnd(ScenePoint2D scenePos)
-  {
-    measureTool_->SetEnd(scenePos);
-  }
-
-  CreateAngleMeasureCommand::CreateAngleMeasureCommand(
-    MessageBroker&    broker, 
-    Scene2D&          scene, 
-    MeasureToolList&  measureTools, 
-    ScenePoint2D      point)
-    : CreateMeasureCommand(scene, measureTools)
-    , measureTool_(new AngleMeasureTool(broker,scene))
-  {
-    measureTools_.push_back(measureTool_);
-    measureTool_->SetSide1End(point);
-    measureTool_->SetCenter(point);
-    measureTool_->SetSide2End(point);
-  }
-
-  /** This method sets center*/
-  void CreateAngleMeasureCommand::SetCenter(ScenePoint2D scenePos)
-  {
-    measureTool_->SetCenter(scenePos);
-  }
-
-  /** This method sets end of side 2*/
-  void CreateAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos)
-  {
-    measureTool_->SetSide2End(scenePos);
-  }
-
-}
--- a/Samples/Common/MeasureCommands.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 <Framework/Scene2D/Scene2D.h>
-#include <boost/shared_ptr.hpp>
-
-// to be moved into Stone
-#include "MeasureTools.h"
-#include "LineMeasureTool.h"
-#include "AngleMeasureTool.h"
-
-namespace OrthancStone
-{
-  //class LineMeasureTool;
-  //typedef boost::shared_ptr<LineMeasureTool> LineMeasureToolPtr;
-  //class AngleMeasureTool;
-  //typedef boost::shared_ptr<AngleMeasureTool> AngleMeasureToolPtr;
-   
-  class TrackerCommand
-  {
-  public:
-    TrackerCommand(Scene2D& scene) : scene_(scene)
-    {
-
-    }
-    virtual void Undo() = 0;
-    virtual void Redo() = 0;
-    Scene2D& GetScene()
-    {
-      return scene_;
-    }
-
-  protected:
-    Scene2D& scene_;
-  private:
-    TrackerCommand(const TrackerCommand&);
-    TrackerCommand& operator=(const TrackerCommand&);
-  };
-
-  typedef boost::shared_ptr<TrackerCommand> TrackerCommandPtr;
-  
-  class CreateMeasureCommand : public TrackerCommand
-  {
-  public:
-    CreateMeasureCommand(Scene2D& scene, MeasureToolList& measureTools);
-    ~CreateMeasureCommand();
-    virtual void Undo() ORTHANC_OVERRIDE;
-    virtual void Redo() ORTHANC_OVERRIDE;
-  protected:
-    MeasureToolList& measureTools_;
-  private:
-    /** Must be implemented by the subclasses that create the actual tool */
-    virtual MeasureToolPtr GetMeasureTool() = 0;
-  };
-
-  typedef boost::shared_ptr<CreateMeasureCommand> CreateMeasureCommandPtr;
-
-  class CreateLineMeasureCommand : public CreateMeasureCommand
-  {
-  public:
-    CreateLineMeasureCommand(
-      MessageBroker& broker, Scene2D& scene, MeasureToolList& measureTools, ScenePoint2D point);
-    
-    // the starting position is set in the ctor
-    void SetEnd(ScenePoint2D scenePos);
-
-  private:
-    virtual MeasureToolPtr GetMeasureTool() ORTHANC_OVERRIDE
-    {
-      return measureTool_;
-    }
-    LineMeasureToolPtr measureTool_;
-  };
-
-  typedef boost::shared_ptr<CreateLineMeasureCommand> CreateLineMeasureCommandPtr;
-
-  class CreateAngleMeasureCommand : public CreateMeasureCommand
-  {
-  public:
-    /** Ctor sets end of side 1*/
-    CreateAngleMeasureCommand(
-      MessageBroker& broker, Scene2D& scene, MeasureToolList& measureTools, ScenePoint2D point);
-
-    /** This method sets center*/
-    void SetCenter(ScenePoint2D scenePos);
-
-    /** This method sets end of side 2*/
-    void SetSide2End(ScenePoint2D scenePos);
-
-  private:
-    virtual MeasureToolPtr GetMeasureTool() ORTHANC_OVERRIDE
-    {
-      return measureTool_;
-    }
-    AngleMeasureToolPtr measureTool_;
-  };
-
-  typedef boost::shared_ptr<CreateAngleMeasureCommand> CreateAngleMeasureCommandPtr;
-}
-
--- a/Samples/Common/MeasureTools.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureTools.h"
-
-#include <Core/Logging.h>
-
-#include <boost/math/constants/constants.hpp>
-
-namespace OrthancStone
-{
-
-  MeasureTool::~MeasureTool()
-  {
-
-  }
-
-  void MeasureTool::Enable()
-  {
-    enabled_ = true;
-    RefreshScene();
-  }
-
-  void MeasureTool::Disable()
-  {
-    enabled_ = false;
-    RefreshScene();
-  }
-
-  bool MeasureTool::IsEnabled() const
-  {
-    return enabled_;
-  }
-
-  OrthancStone::Scene2D& MeasureTool::GetScene()
-  {
-    return scene_;
-  }
-
-  MeasureTool::MeasureTool(MessageBroker& broker, Scene2D& scene)
-    : IObserver(broker)
-    , scene_(scene)
-    , enabled_(true)
-  {
-    scene_.RegisterObserverCallback(
-      new Callable<MeasureTool, Scene2D::SceneTransformChanged>
-      (*this, &MeasureTool::OnSceneTransformChanged));
-  }
-
-  void MeasureTool::OnSceneTransformChanged(
-    const Scene2D::SceneTransformChanged& message)
-  {
-    RefreshScene();
-  }
-
-
-}
-
--- a/Samples/Common/MeasureTools.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 <Framework/Scene2D/Scene2D.h>
-#include <Framework/Scene2D/ScenePoint2D.h>
-#include <Framework/Scene2D/PolylineSceneLayer.h>
-#include <Framework/Scene2D/TextSceneLayer.h>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-#include <vector>
-#include <cmath>
-
-namespace OrthancStone
-{
-  class MeasureTool : public IObserver
-  {
-  public:
-    virtual ~MeasureTool();
-
-    /**
-    Enabled tools are rendered in the scene.
-    */
-    void Enable();
-
-    /**
-    Disabled tools are not rendered in the scene. This is useful to be able
-    to use them as their own memento in command stacks (when a measure tool
-    creation command has been undone, the measure remains alive in the
-    command object but is disabled so that it can be redone later on easily)
-    */
-    void Disable();
-
-    /**
-    This method is called when the scene transform changes. It allows to 
-    recompute the visual elements whose content depend upon the scene transform
-    */
-    void OnSceneTransformChanged(const Scene2D::SceneTransformChanged& message);
-
-  protected:
-    MeasureTool(MessageBroker& broker, Scene2D& scene);
-    
-    /**
-    This is the meat of the tool: this method must [create (if needed) and]
-    update the layers and their data according to the measure tool kind and
-    current state. This is repeatedly called during user interaction
-    */
-    virtual void RefreshScene() = 0;
-
-    Scene2D& GetScene();
-
-    /**
-    enabled_ is not accessible by subclasses because there is a state machine
-    that we do not wanna mess with
-    */
-    bool IsEnabled() const;
-
-  private:
-    Scene2D& scene_;
-    bool     enabled_;
-  };
-
-  typedef boost::shared_ptr<MeasureTool> MeasureToolPtr;
-  typedef std::vector<MeasureToolPtr> MeasureToolList;
-}
-
-
-extern void TrackerSample_SetInfoDisplayMessage(
-  std::string key, std::string value);
--- a/Samples/Common/MeasureToolsToolbox.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureToolsToolbox.h"
-
-#include <boost/math/constants/constants.hpp>
-
-namespace
-{
-  double g_pi = boost::math::constants::pi<double>();
-}
-
-namespace OrthancStone
-{
-  double RadiansToDegrees(double angleRad)
-  {
-    static const double factor = 180.0 / g_pi;
-    return angleRad * factor;
-  }
-
-  void AddSquare(PolylineSceneLayer::Chain& chain,
-    const Scene2D&      scene,
-    const ScenePoint2D& centerS,
-    const double&       sideLength)
-  {
-    chain.clear();
-    chain.reserve(4);
-    ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
-    //TODO: take DPI into account 
-    double handleLX = centerC.GetX() - sideLength / 2;
-    double handleTY = centerC.GetY() - sideLength / 2;
-    double handleRX = centerC.GetX() + sideLength / 2;
-    double handleBY = centerC.GetY() + sideLength / 2;
-    ScenePoint2D LTC(handleLX, handleTY);
-    ScenePoint2D RTC(handleRX, handleTY);
-    ScenePoint2D RBC(handleRX, handleBY);
-    ScenePoint2D LBC(handleLX, handleBY);
-
-    ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
-    ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
-    ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
-    ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
-
-    chain.push_back(startLT);
-    chain.push_back(startRT);
-    chain.push_back(startRB);
-    chain.push_back(startLB);
-  }
-#if 0
-  void AddArc(
-      PolylineSceneLayer::Chain& chain
-    , const Scene2D&      scene
-    , const ScenePoint2D& p1
-    , const ScenePoint2D& c
-    , const ScenePoint2D& p2
-    , const double&       radiusS
-    , const bool          clockwise
-    , const int           subdivisionsCount)
-  {
-    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
-    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
-    AddArc(
-      chain, scene, c, radiusS, p1cAngle, p2cAngle, 
-      clockwise, subdivisionsCount);
-  }
-#endif
-
-  void AddShortestArc(
-      PolylineSceneLayer::Chain& chain
-    , const Scene2D&             scene
-    , const ScenePoint2D&        p1
-    , const ScenePoint2D&        c
-    , const ScenePoint2D&        p2
-    , const double&              radiusS
-    , const int                  subdivisionsCount)
-  {
-    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
-    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
-    AddShortestArc(
-      chain, scene, c, radiusS, p1cAngle, p2cAngle, subdivisionsCount);
-  }
-
-  void GetPositionOnBisectingLine(
-    ScenePoint2D&       result
-    , const ScenePoint2D& p1
-    , const ScenePoint2D& c
-    , const ScenePoint2D& p2
-    , const double d)
-  {
-    // TODO: fix correct half-plane
-    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
-    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
-    double angle = 0.5*(p1cAngle + p2cAngle);
-    double unitVectorX = cos(angle);
-    double unitVectorY = sin(angle);
-    double posX = c.GetX() + d * unitVectorX;
-    double posY = c.GetX() + d * unitVectorY;
-    result = ScenePoint2D(posX, posY);
-  }
-   
-
-  void AddShortestArc(
-      PolylineSceneLayer::Chain&  chain
-    , const Scene2D&              scene
-    , const ScenePoint2D&         centerS
-    , const double&               radiusS
-    , const double                startAngleRad
-    , const double                endAngleRad
-    , const int                   subdivisionsCount)
-  {
-    // this gives a signed difference between angle which
-    // is the smallest difference (in magnitude) between 
-    // the angles
-    double delta = NormalizeAngle(endAngleRad-startAngleRad);
-
-    chain.clear();
-    chain.reserve(subdivisionsCount + 1);
-
-    double angleIncr = delta/static_cast<double>(subdivisionsCount);
-
-    double theta = startAngleRad;
-    for (int i = 0; i < subdivisionsCount + 1; ++i)
-    {
-      double offsetX = radiusS * cos(theta);
-      double offsetY = radiusS * sin(theta);
-      double pointX = centerS.GetX() + offsetX;
-      double pointY = centerS.GetY() + offsetY;
-      chain.push_back(ScenePoint2D(pointX, pointY));
-      theta += angleIncr;
-    }
-  }
-
-#if 0
-  void AddArc(
-      PolylineSceneLayer::Chain& chain
-    , const Scene2D&      scene
-    , const ScenePoint2D& centerS
-    , const double&       radiusS
-    , const double        startAngleRad
-    , const double        endAngleRad
-    , const bool          clockwise
-    , const int           subdivisionsCount)
-  {
-    double startAngleRadN = NormalizeAngle(startAngleRad);
-    double endAngleRadN = NormalizeAngle(endAngleRad);
-
-    double angle1Rad = std::min(startAngleRadN, endAngleRadN);
-    double angle2Rad = std::max(startAngleRadN, endAngleRadN);
-
-    // now we are sure angle1Rad < angle2Rad
-    // this means that if we draw from 1 to 2, it will be clockwise (
-    // increasing angles).
-    // let's fix this:
-    if (!clockwise)
-    {
-      angle2Rad -= 2 * g_pi;
-      // now we are sure angle2Rad < angle1Rad (since they were normalized) 
-      // and, thus, going from 1 to 2 means the angle values will DECREASE,
-      // which is the definition of anticlockwise
-    }
-
-    chain.clear();
-    chain.reserve(subdivisionsCount + 1);
-
-    double angleIncr = (angle2Rad - angle1Rad)
-      / static_cast<double>(subdivisionsCount);
-
-    double theta = angle1Rad;
-    for (int i = 0; i < subdivisionsCount + 1; ++i)
-    {
-      double offsetX = radiusS * cos(theta);
-      double offsetY = radiusS * sin(theta);
-      double pointX = centerS.GetX() + offsetX;
-      double pointY = centerS.GetY() + offsetY;
-      chain.push_back(ScenePoint2D(pointX, pointY));
-      theta += angleIncr;
-    }
-  }
-#endif
-
-  void AddCircle(PolylineSceneLayer::Chain& chain,
-    const Scene2D&      scene,
-    const ScenePoint2D& centerS,
-    const double&       radiusS,
-    const int           numSubdivisions)
-  {
-    //ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
-    //TODO: take DPI into account
-
-    // TODO: automatically compute the number for segments for smooth 
-    // display based on the radius in pixels.
-
-    chain.clear();
-    chain.reserve(numSubdivisions);
-
-    double angleIncr = (2.0 * g_pi)
-      / static_cast<double>(numSubdivisions);
-
-    double theta = 0;
-    for (int i = 0; i < numSubdivisions; ++i)
-    {
-      double offsetX = radiusS * cos(theta);
-      double offsetY = radiusS * sin(theta);
-      double pointX = centerS.GetX() + offsetX;
-      double pointY = centerS.GetY() + offsetY;
-      chain.push_back(ScenePoint2D(pointX, pointY));
-      theta += angleIncr;
-    }
-  }
-
-  double NormalizeAngle(double angle)
-  {
-    double retAngle = angle;
-    while (retAngle < -1.0*g_pi)
-      retAngle += 2 * g_pi;
-    while (retAngle >= g_pi)
-      retAngle -= 2 * g_pi;
-    return retAngle;
-  }
-
-  double MeasureAngle(const ScenePoint2D& p1, const ScenePoint2D& c, const ScenePoint2D& p2)
-  {
-    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
-    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
-    double delta = p2cAngle - p1cAngle;
-    return NormalizeAngle(delta);
-  }
-
-
-#if 0
-  void AddEllipse(PolylineSceneLayer::Chain& chain,
-    const Scene2D&      scene,
-    const ScenePoint2D& centerS,
-    const double&       halfHAxis,
-    const double&       halfVAxis)
-  {
-    chain.clear();
-    chain.reserve(4);
-    ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
-    //TODO: take DPI into account
-    double handleLX = centerC.GetX() - sideLength / 2;
-    double handleTY = centerC.GetY() - sideLength / 2;
-    double handleRX = centerC.GetX() + sideLength / 2;
-    double handleBY = centerC.GetY() + sideLength / 2;
-    ScenePoint2D LTC(handleLX, handleTY);
-    ScenePoint2D RTC(handleRX, handleTY);
-    ScenePoint2D RBC(handleRX, handleBY);
-    ScenePoint2D LBC(handleLX, handleBY);
-
-    ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
-    ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
-    ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
-    ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
-
-    chain.push_back(startLT);
-    chain.push_back(startRT);
-    chain.push_back(startRB);
-    chain.push_back(startLB);
-}
-#endif
-}
--- a/Samples/Common/MeasureToolsToolbox.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 <Framework/Scene2D/PolylineSceneLayer.h>
-#include <Framework/Scene2D/Scene2D.h>
-
-namespace OrthancStone
-{
-
-  /**
-  This function will create a square around the center point supplied in
-  scene coordinates, with a side length given in canvas coordinates. The
-  square sides are parallel to the canvas boundaries.
-  */
-  void AddSquare(PolylineSceneLayer::Chain& chain,
-    const Scene2D&      scene,
-    const ScenePoint2D& centerS,
-    const double&       sideLength);
-
-
-  /**
-    Creates an arc centered on c that goes
-    - from a point r1:
-      - so that r1 belongs to the p1,c line
-      - so that the distance from c to r1 equals radius
-    - to a point r2:
-      - so that r2 belongs to the p2,c line
-      - so that the distance from c to r2 equals radius
-    - that follows the shortest among the two possible paths
-
-    Warning: the existing chain content will be wiped out.
-  */
-  void AddShortestArc(
-      PolylineSceneLayer::Chain&  chain
-    , const Scene2D&              scene
-    , const ScenePoint2D&         p1
-    , const ScenePoint2D&         c
-    , const ScenePoint2D&         p2
-    , const double&               radiusS
-    , const int                   subdivisionsCount = 63);
-
-  /**
-    Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from 
-    start angle to end angle, by following the shortest arc.
-
-    Warning: the existing chain content will be wiped out.
-  */
-  void AddShortestArc(
-      PolylineSceneLayer::Chain&  chain
-    , const Scene2D&              scene
-    , const ScenePoint2D&         centerS
-    , const double&               radiusS
-    , const double                startAngleRad
-    , const double                endAngleRad
-    , const int                   subdivisionsCount = 63);
-
-#if 0
-  /**
-    Creates an arc centered on c that goes
-    - from a point r1:
-      - so that r1 belongs to the p1,c line
-      - so that the distance from c to r1 equals radius
-    - to a point r2:
-      - so that r2 belongs to the p2,c line
-      - so that the distance from c to r2 equals radius
-
-    if clockwise is true, the arc is drawn from r1 to r2 with increasing 
-    angle values. Otherwise, the angle values decrease.
-
-    Warning: the existing chain content will be wiped out.
-  */
-
-  void AddArc(
-      PolylineSceneLayer::Chain& chain
-    , const Scene2D&             scene
-    , const ScenePoint2D&        p1
-    , const ScenePoint2D&        c
-    , const ScenePoint2D&        p2
-    , const double&              radiusS
-    , const bool                 clockwise
-    , const int                  subdivisionsCount = 63);
- 
-  /**
-    Creates an arc (open curve) with "numSubdivisions" (N + 1 points) from 
-    start angle to end angle with the supplied radius.
-
-    if clockwise is true, the arc is drawn from start to end by increasing the
-    angle values.
-
-    Otherwise, the angle value decreases from start to end.
-
-    Warning: the existing chain content will be wiped out.
-  */
-  void AddArc(
-      PolylineSceneLayer::Chain& chain
-    , const Scene2D&      scene
-    , const ScenePoint2D& centerS
-    , const double&       radiusS
-    , const double        startAngleRad
-    , const double        endAngleRad
-    , const bool          clockwise
-    , const int           subdivisionsCount = 63);
-#endif
-  /**
-    Creates a circle (closed curve) with "numSubdivisions"
-    (N points)
-
-    Warning: the existing chain content will be wiped out.
-  */
-  void AddCircle(PolylineSceneLayer::Chain& chain,
-    const Scene2D&      scene,
-    const ScenePoint2D& centerS,
-    const double&       radiusS,
-    const int           numSubdivisions = 63);
-
-  /**
-    Adds or subtracts 2*pi as many times as need to shift the specified
-    angle to a value such as: -pi <= value < pi
-   */
-  double NormalizeAngle(double angle);
-
-  /**
-    Returns the angle magnitude between the p1,c and p2,c lines. 
-    The returned angle is between 0 and 2*pi
-
-    If the angle is between 0 and pi, this means that the shortest arc 
-    from p1 to p2 is clockwise.
-
-    If the angle is between pi and 2*pi, this means that the shortest arc
-    from p1 to p2 is COUNTERclockwise.
-
-  */
-  double MeasureAngle(
-      const ScenePoint2D& p1
-    , const ScenePoint2D& c
-    , const ScenePoint2D& p2);
-
-  /**
-  RadiansToDegrees
-  */
-  double RadiansToDegrees(double angleRad);
-
-  /**
-  This function will return the coordinates of a point that:
-  - belongs to the two bisecting lines of the p1 c p2 angle.
-  - is a distance d from c.
-  Among the four possible points, the one returned will be the one belonging
-  to the *smallest* half-plane defined by the [c,p1[ and [c,p2[ half-lines.
-  */
-  void GetPositionOnBisectingLine(
-      ScenePoint2D&       result
-    , const ScenePoint2D& p1
-    , const ScenePoint2D& c
-    , const ScenePoint2D& p2
-    , const double d);
-}
--- a/Samples/Common/MeasureTrackers.cpp	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MeasureTrackers.h"
-#include <Core/OrthancException.h>
-
-using namespace Orthanc;
-
-namespace OrthancStone
-{
-
-  CreateMeasureTracker::CreateMeasureTracker(
-    Scene2D&                        scene,
-    std::vector<TrackerCommandPtr>& undoStack,
-    std::vector<MeasureToolPtr>&    measureTools)
-    : scene_(scene)
-    , active_(true)
-    , undoStack_(undoStack)
-    , measureTools_(measureTools)
-    , commitResult_(true)
-  {
-  }
-
-  void CreateMeasureTracker::Cancel()
-  {
-    commitResult_ = false;
-    active_ = false;
-  }
-
-  bool CreateMeasureTracker::IsActive() const
-  {
-    return active_;
-  }
-
-  CreateMeasureTracker::~CreateMeasureTracker()
-  {
-    // if the tracker completes successfully, we add the command
-    // to the undo stack
-
-    // otherwise, we simply undo it
-    if (commitResult_)
-      undoStack_.push_back(command_);
-    else
-      command_->Undo();
-  }
-}
-
-
--- a/Samples/Common/MeasureTrackers.h	Thu May 16 19:10:38 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IFlexiblePointerTracker.h"
-#include "../../Framework/Scene2D/Scene2D.h"
-#include "../../Framework/Scene2D/PointerEvent.h"
-
-#include "MeasureTools.h"
-#include "MeasureCommands.h"
-
-#include <vector>
-
-namespace OrthancStone
-{
-  class CreateMeasureTracker : public IFlexiblePointerTracker
-  {
-  public:
-    virtual void Cancel() ORTHANC_OVERRIDE;
-    virtual bool IsActive() const ORTHANC_OVERRIDE;
-  protected:
-    CreateMeasureTracker(
-      Scene2D&                        scene,
-      std::vector<TrackerCommandPtr>& undoStack,
-      std::vector<MeasureToolPtr>&    measureTools);
-
-    ~CreateMeasureTracker();
-  
-  protected:
-    CreateMeasureCommandPtr         command_;
-    Scene2D&                        scene_;
-    bool                            active_;
-  private:
-    std::vector<TrackerCommandPtr>& undoStack_;
-    std::vector<MeasureToolPtr>&    measureTools_;
-    bool                            commitResult_;
-  };
-}
-
--- a/Samples/Sdl/BasicScene.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Samples/Sdl/BasicScene.cpp	Tue May 21 13:25:58 2019 +0200
@@ -28,6 +28,8 @@
 #include "../../Framework/Scene2D/RotateSceneTracker.h"
 #include "../../Framework/Scene2D/Scene2D.h"
 #include "../../Framework/Scene2D/ZoomSceneTracker.h"
+#include "../../Framework/Scene2DViewport/ViewportController.h"
+
 #include "../../Framework/StoneInitialization.h"
 #include "../../Framework/Messages/MessageBroker.h"
 
@@ -38,17 +40,20 @@
 #include <Core/Images/ImageProcessing.h>
 #include <Core/Images/PngWriter.h>
 
+#include <boost/make_shared.hpp>
+#include <boost/ref.hpp>
+
 #include <SDL.h>
 #include <stdio.h>
 
 static const unsigned int FONT_SIZE = 32;
 static const int LAYER_POSITION = 150;
 
+using namespace OrthancStone;
 
-void PrepareScene(OrthancStone::Scene2D& scene)
+void PrepareScene(ViewportControllerPtr controller)
 {
-  using namespace OrthancStone;
-
+  Scene2D& scene(*controller->GetScene());
   // Texture of 2x2 size
   {
     Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false);
@@ -137,12 +142,12 @@
 
 
 void TakeScreenshot(const std::string& target,
-                    const OrthancStone::Scene2D& scene,
+                    const Scene2D& scene,
                     unsigned int canvasWidth,
                     unsigned int canvasHeight)
 {
   // Take a screenshot, then save it as PNG file
-  OrthancStone::CairoCompositor compositor(scene, canvasWidth, canvasHeight);
+  CairoCompositor compositor(scene, canvasWidth, canvasHeight);
   compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE, Orthanc::Encoding_Latin1);
   compositor.Refresh();
 
@@ -157,11 +162,12 @@
 }
 
 
-void HandleApplicationEvent(OrthancStone::Scene2D& scene,
-                            const OrthancStone::OpenGLCompositor& compositor,
+void HandleApplicationEvent(ViewportControllerPtr controller,
+                            const OpenGLCompositor& compositor,
                             const SDL_Event& event,
-                            std::auto_ptr<OrthancStone::IPointerTracker>& activeTracker)
+                            FlexiblePointerTrackerPtr& activeTracker)
 {
+  Scene2D& scene(*controller->GetScene());
   if (event.type == SDL_MOUSEMOTION)
   {
     int scancodeCount = 0;
@@ -173,28 +179,29 @@
     {
       // The "left-ctrl" key is down, while no tracker is present
 
-      OrthancStone::PointerEvent e;
+      PointerEvent e;
       e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y));
 
-      OrthancStone::ScenePoint2D p = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
+      ScenePoint2D p = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
 
       char buf[64];
       sprintf(buf, "(%0.02f,%0.02f)", p.GetX(), p.GetY());
 
       if (scene.HasLayer(LAYER_POSITION))
       {
-        OrthancStone::TextSceneLayer& layer =
-          dynamic_cast<OrthancStone::TextSceneLayer&>(scene.GetLayer(LAYER_POSITION));
+        TextSceneLayer& layer =
+          dynamic_cast<TextSceneLayer&>(scene.GetLayer(LAYER_POSITION));
         layer.SetText(buf);
         layer.SetPosition(p.GetX(), p.GetY());
       }
       else
       {
-        std::auto_ptr<OrthancStone::TextSceneLayer> layer(new OrthancStone::TextSceneLayer);
+        std::auto_ptr<TextSceneLayer> 
+          layer(new TextSceneLayer);
         layer->SetColor(0, 255, 0);
         layer->SetText(buf);
         layer->SetBorder(20);
-        layer->SetAnchor(OrthancStone::BitmapAnchor_BottomCenter);
+        layer->SetAnchor(BitmapAnchor_BottomCenter);
         layer->SetPosition(p.GetX(), p.GetY());
         scene.SetLayer(LAYER_POSITION, layer.release());
       }
@@ -206,22 +213,22 @@
   }
   else if (event.type == SDL_MOUSEBUTTONDOWN)
   {
-    OrthancStone::PointerEvent e;
+    PointerEvent e;
     e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y));
 
     switch (event.button.button)
     {
       case SDL_BUTTON_MIDDLE:
-        activeTracker.reset(new OrthancStone::PanSceneTracker(scene, e));
+        activeTracker = boost::make_shared<PanSceneTracker>(controller, e);
         break;
 
       case SDL_BUTTON_RIGHT:
-        activeTracker.reset(new OrthancStone::ZoomSceneTracker(scene, e, 
-                                                               compositor.GetCanvasHeight()));
+        activeTracker = boost::make_shared<ZoomSceneTracker>(controller, 
+          e, compositor.GetCanvasHeight());
         break;
 
       case SDL_BUTTON_LEFT:
-        activeTracker.reset(new OrthancStone::RotateSceneTracker(scene, e));
+        activeTracker = boost::make_shared<RotateSceneTracker>(controller, e);
         break;
 
       default:
@@ -234,7 +241,7 @@
     switch (event.key.keysym.sym)
     {
       case SDLK_s:
-        scene.FitContent(compositor.GetCanvasWidth(), 
+        controller->FitContent(compositor.GetCanvasWidth(), 
                          compositor.GetCanvasHeight());
         break;
               
@@ -269,20 +276,20 @@
 }
 
 
-void Run(OrthancStone::Scene2D& scene)
+void Run(ViewportControllerPtr controller)
 {
-  OrthancStone::SdlOpenGLWindow window("Hello", 1024, 768);
+  SdlOpenGLWindow window("Hello", 1024, 768);
 
-  scene.FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
+  controller->FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
   
   glEnable(GL_DEBUG_OUTPUT);
   glDebugMessageCallback(OpenGLMessageCallback, 0);
 
-  OrthancStone::OpenGLCompositor compositor(window, scene);
+  OpenGLCompositor compositor(window, *controller->GetScene());
   compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, 
                      FONT_SIZE, Orthanc::Encoding_Latin1);
 
-  std::auto_ptr<OrthancStone::IPointerTracker>  tracker;
+  FlexiblePointerTrackerPtr tracker;
 
   bool stop = false;
   while (!stop)
@@ -300,25 +307,30 @@
       }
       else if (event.type == SDL_MOUSEMOTION)
       {
-        if (tracker.get() != NULL)
+        if (tracker)
         {
-          OrthancStone::PointerEvent e;
-          e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y));
-          tracker->Update(e);
+          PointerEvent e;
+          e.AddPosition(compositor.GetPixelCenterCoordinates(
+            event.button.x, event.button.y));
+          tracker->PointerMove(e);
         }
       }
       else if (event.type == SDL_MOUSEBUTTONUP)
       {
-        if (tracker.get() != NULL)
+        if (tracker)
         {
-          tracker->Release();
-          tracker.reset(NULL);
+          PointerEvent e;
+          e.AddPosition(compositor.GetPixelCenterCoordinates(
+            event.button.x, event.button.y));
+          tracker->PointerUp(e);
+          if(!tracker->IsAlive())
+            tracker.reset();
         }
       }
       else if (event.type == SDL_WINDOWEVENT &&
                event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
       {
-        tracker.reset(NULL);
+        tracker.reset();
         compositor.UpdateSize();
       }
       else if (event.type == SDL_KEYDOWN &&
@@ -339,7 +351,7 @@
         }
       }
       
-      HandleApplicationEvent(scene, compositor, event, tracker);
+      HandleApplicationEvent(controller, compositor, event, tracker);
     }
 
     SDL_Delay(1);
@@ -356,22 +368,23 @@
  **/
 int main(int argc, char* argv[])
 {
-  OrthancStone::StoneInitialize();
+  StoneInitialize();
   Orthanc::Logging::EnableInfoLevel(true);
 
   try
   {
-    OrthancStone::MessageBroker broker;
-    OrthancStone::Scene2D scene(broker);
-    PrepareScene(scene);
-    Run(scene);
+    MessageBroker broker;
+    ViewportControllerPtr controller = boost::make_shared<ViewportController>(
+		boost::ref(broker));
+    PrepareScene(controller);
+    Run(controller);
   }
   catch (Orthanc::OrthancException& e)
   {
     LOG(ERROR) << "EXCEPTION: " << e.What();
   }
 
-  OrthancStone::StoneFinalize();
+  StoneFinalize();
 
   return 0;
 }
--- a/Samples/Sdl/CMakeLists.txt	Thu May 16 19:10:38 2019 +0200
+++ b/Samples/Sdl/CMakeLists.txt	Tue May 21 13:25:58 2019 +0200
@@ -69,44 +69,6 @@
   LIST(APPEND TRACKERSAMPLE_SOURCE "../../../SDL-Console/SDL_Console.h")
 endif()
 
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/AngleMeasureTool.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/AngleMeasureTool.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateAngleMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateAngleMeasureTracker.h")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateCircleMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateCircleMeasureTracker.h")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateLineMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateLineMeasureTracker.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateMeasureTracker.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateSimpleTrackerAdapter.cpp")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/EditAngleMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/EditAngleMeasureTracker.h")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/EditCircleMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/EditCircleMeasureTracker.h")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/EditLineMeasureTracker.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/EditLineMeasureTracker.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/IFlexiblePointerTracker.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/LineMeasureTool.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/LineMeasureTool.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureCommands.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureCommands.h")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTools.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTools.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureToolsToolbox.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureToolsToolbox.h")
-
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTrackers.cpp")
-LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTrackers.h")
-
 LIST(APPEND TRACKERSAMPLE_SOURCE "TrackerSample.cpp")
 LIST(APPEND TRACKERSAMPLE_SOURCE "TrackerSampleApp.cpp")
 LIST(APPEND TRACKERSAMPLE_SOURCE "TrackerSampleApp.h")
--- a/Samples/Sdl/Loader.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Samples/Sdl/Loader.cpp	Tue May 21 13:25:58 2019 +0200
@@ -19,14 +19,19 @@
  **/
 
 // From Stone
+#include "../../Framework/Loaders/BasicFetchingItemsSorter.h"
+#include "../../Framework/Loaders/BasicFetchingStrategy.h"
 #include "../../Framework/Messages/ICallable.h"
 #include "../../Framework/Messages/IMessage.h"
 #include "../../Framework/Messages/IObservable.h"
 #include "../../Framework/Messages/MessageBroker.h"
+#include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
+#include "../../Framework/Scene2D/FloatTextureSceneLayer.h"
+#include "../../Framework/Scene2D/Scene2D.h"
 #include "../../Framework/StoneInitialization.h"
 #include "../../Framework/Toolbox/GeometryToolbox.h"
+#include "../../Framework/Toolbox/SlicesSorter.h"
 #include "../../Framework/Volumes/ImageBuffer3D.h"
-#include "../../Framework/Toolbox/SlicesSorter.h"
 
 // From Orthanc framework
 #include <Core/Compression/GzipCompressor.h>
@@ -44,8 +49,8 @@
 #include <Core/Logging.h>
 #include <Core/MultiThreading/SharedMessageQueue.h>
 #include <Core/OrthancException.h>
+#include <Core/SystemToolbox.h>
 #include <Core/Toolbox.h>
-#include <Core/SystemToolbox.h>
 
 #include <json/reader.h>
 #include <json/value.h>
@@ -101,6 +106,17 @@
 
 
 
+  class IVolumeSlicer : public boost::noncopyable
+  {
+  public:
+    virtual ~IVolumeSlicer()
+    {
+    }
+
+    virtual void SetViewportPlane(const OrthancStone::CoordinateSystem3D& plane) = 0;
+  };
+
+
 
   class OracleCommandWithPayload : public IOracleCommand
   {
@@ -354,9 +370,11 @@
 
 
   private:
-    std::string    uri_;
-    HttpHeaders    headers_;
-    unsigned int   timeout_;
+    std::string           uri_;
+    HttpHeaders           headers_;
+    unsigned int          timeout_;
+    bool                  hasExpectedFormat_;
+    Orthanc::PixelFormat  expectedFormat_;
 
     std::auto_ptr< OrthancStone::MessageHandler<SuccessMessage> >  successCallback_;
     std::auto_ptr< OrthancStone::MessageHandler<OracleCommandExceptionMessage> >  failureCallback_;
@@ -364,7 +382,8 @@
   public:
     GetOrthancImageCommand() :
       uri_("/"),
-      timeout_(10)
+      timeout_(10),
+      hasExpectedFormat_(false)
     {
     }
 
@@ -373,11 +392,41 @@
       return Type_GetOrthancImage;
     }
 
+    void SetExpectedPixelFormat(Orthanc::PixelFormat format)
+    {
+      hasExpectedFormat_ = true;
+      expectedFormat_ = format;
+    }
+
     void SetUri(const std::string& uri)
     {
       uri_ = uri;
     }
 
+    void SetInstanceUri(const std::string& instance,
+                        Orthanc::PixelFormat pixelFormat)
+    {
+      uri_ = "/instances/" + instance;
+          
+      switch (pixelFormat)
+      {
+        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);
+      }
+    }
+
     void SetHttpHeader(const std::string& key,
                        const std::string& value)
     {
@@ -455,6 +504,20 @@
                                           std::string(Orthanc::EnumerationToString(contentType)));
       }
 
+      if (hasExpectedFormat_)
+      {
+        if (expectedFormat_ == Orthanc::PixelFormat_SignedGrayscale16 &&
+            image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
+        {
+          image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
+        }
+
+        if (expectedFormat_ != image->GetFormat())
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+        }
+      }
+
       SuccessMessage message(*this, image.release(), contentType);
       emitter.EmitMessage(receiver, message);
     }
@@ -515,7 +578,7 @@
       return Type_GetOrthancWebViewerJpeg;
     }
 
-    void SetExpectedFormat(Orthanc::PixelFormat format)
+    void SetExpectedPixelFormat(Orthanc::PixelFormat format)
     {
       expectedFormat_ = format;
     }
@@ -549,7 +612,7 @@
       headers_[key] = value;
     }
 
-    Orthanc::PixelFormat GetExpectedFormat() const
+    Orthanc::PixelFormat GetExpectedPixelFormat() const
     {
       return expectedFormat_;
     }
@@ -734,6 +797,1127 @@
 
 
 
+  class DicomInstanceParameters :
+    public Orthanc::IDynamicObject  /* to be used as a payload of SlicesSorter */
+  {
+  private:
+    struct Data   // Struct to ease the copy constructor
+    {
+      std::string                       orthancInstanceId_;
+      std::string                       studyInstanceUid_;
+      std::string                       seriesInstanceUid_;
+      std::string                       sopInstanceUid_;
+      Orthanc::DicomImageInformation    imageInformation_;
+      OrthancStone::SopClassUid         sopClassUid_;
+      double                            thickness_;
+      double                            pixelSpacingX_;
+      double                            pixelSpacingY_;
+      OrthancStone::CoordinateSystem3D  geometry_;
+      OrthancStone::Vector              frameOffsets_;
+      bool                              isColor_;
+      bool                              hasRescale_;
+      double                            rescaleIntercept_;
+      double                            rescaleSlope_;
+      bool                              hasDefaultWindowing_;
+      float                             defaultWindowingCenter_;
+      float                             defaultWindowingWidth_;
+      Orthanc::PixelFormat              expectedPixelFormat_;
+
+      void ComputeDoseOffsets(const Orthanc::DicomMap& dicom)
+      {
+        // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html
+
+        {
+          std::string increment;
+
+          if (dicom.CopyToString(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false))
+          {
+            Orthanc::Toolbox::ToUpperCase(increment);
+            if (increment != "3004,000C")  // This is the "Grid Frame Offset Vector" tag
+            {
+              LOG(ERROR) << "RT-DOSE: Bad value for the \"FrameIncrementPointer\" tag";
+              return;
+            }
+          }
+        }
+
+        if (!OrthancStone::LinearAlgebra::ParseVector(frameOffsets_, dicom, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) ||
+            frameOffsets_.size() < imageInformation_.GetNumberOfFrames())
+        {
+          LOG(ERROR) << "RT-DOSE: No information about the 3D location of some slice(s)";
+          frameOffsets_.clear();
+        }
+        else
+        {
+          if (frameOffsets_.size() >= 2)
+          {
+            thickness_ = frameOffsets_[1] - frameOffsets_[0];
+
+            if (thickness_ < 0)
+            {
+              thickness_ = -thickness_;
+            }
+          }
+        }
+      }
+
+      Data(const Orthanc::DicomMap& dicom) :
+        imageInformation_(dicom)
+      {
+        if (imageInformation_.GetNumberOfFrames() <= 0)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        }
+
+        if (!dicom.CopyToString(studyInstanceUid_, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) ||
+            !dicom.CopyToString(seriesInstanceUid_, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false) ||
+            !dicom.CopyToString(sopInstanceUid_, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false))
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        }
+        
+        std::string s;
+        if (!dicom.CopyToString(s, Orthanc::DICOM_TAG_SOP_CLASS_UID, false))
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        }
+        else
+        {
+          sopClassUid_ = OrthancStone::StringToSopClassUid(s);
+        }
+
+        if (!dicom.ParseDouble(thickness_, Orthanc::DICOM_TAG_SLICE_THICKNESS))
+        {
+          thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
+        }
+
+        OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dicom);
+
+        std::string position, orientation;
+        if (dicom.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) &&
+            dicom.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false))
+        {
+          geometry_ = OrthancStone::CoordinateSystem3D(position, orientation);
+        }
+
+        if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
+        {
+          ComputeDoseOffsets(dicom);
+        }
+
+        isColor_ = (imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome1 &&
+                    imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome2);
+
+        double doseGridScaling;
+
+        if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) &&
+            dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE))
+        {
+          hasRescale_ = true;
+        }
+        else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING))
+        {
+          hasRescale_ = true;
+          rescaleIntercept_ = 0;
+          rescaleSlope_ = doseGridScaling;
+        }
+        else
+        {
+          hasRescale_ = false;
+        }
+
+        OrthancStone::Vector c, w;
+        if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
+            OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
+            c.size() > 0 && 
+            w.size() > 0)
+        {
+          hasDefaultWindowing_ = true;
+          defaultWindowingCenter_ = static_cast<float>(c[0]);
+          defaultWindowingWidth_ = static_cast<float>(w[0]);
+        }
+        else
+        {
+          hasDefaultWindowing_ = false;
+        }
+
+        if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
+        {
+          switch (imageInformation_.GetBitsStored())
+          {
+            case 16:
+              expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+              break;
+
+            case 32:
+              expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
+              break;
+
+            default:
+              throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+          } 
+        }
+        else if (isColor_)
+        {
+          expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
+        }
+        else if (imageInformation_.IsSigned())
+        {
+          expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
+        }
+        else
+        {
+          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+        }
+      }
+
+      OrthancStone::CoordinateSystem3D  GetFrameGeometry(unsigned int frame) const
+      {
+        if (frame == 0)
+        {
+          return geometry_;
+        }
+        else if (frame >= imageInformation_.GetNumberOfFrames())
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+        else if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
+        {
+          if (frame >= frameOffsets_.size())
+          {
+            throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+          }
+
+          return OrthancStone::CoordinateSystem3D(
+            geometry_.GetOrigin() + frameOffsets_[frame] * geometry_.GetNormal(),
+            geometry_.GetAxisX(),
+            geometry_.GetAxisY());
+        }
+        else
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+        }
+      }
+
+      // TODO - Is this necessary?
+      bool FrameContainsPlane(unsigned int frame,
+                              const OrthancStone::CoordinateSystem3D& plane) const
+      {
+        if (frame >= imageInformation_.GetNumberOfFrames())
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        OrthancStone::CoordinateSystem3D tmp = geometry_;
+
+        if (frame != 0)
+        {
+          tmp = GetFrameGeometry(frame);
+        }
+
+        double distance;
+
+        return (OrthancStone::CoordinateSystem3D::GetDistance(distance, tmp, plane) &&
+                distance <= thickness_ / 2.0);
+      }
+
+      
+      void ApplyRescale(Orthanc::ImageAccessor& image,
+                        bool useDouble) const
+      {
+        if (image.GetFormat() != Orthanc::PixelFormat_Float32)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+        }
+    
+        if (hasRescale_)
+        {
+          const unsigned int width = image.GetWidth();
+          const unsigned int height = image.GetHeight();
+        
+          for (unsigned int y = 0; y < height; y++)
+          {
+            float* p = reinterpret_cast<float*>(image.GetRow(y));
+
+            if (useDouble)
+            {
+              // Slower, accurate implementation using double
+              for (unsigned int x = 0; x < width; x++, p++)
+              {
+                double value = static_cast<double>(*p);
+                *p = static_cast<float>(value * rescaleSlope_ + rescaleIntercept_);
+              }
+            }
+            else
+            {
+              // Fast, approximate implementation using float
+              for (unsigned int x = 0; x < width; x++, p++)
+              {
+                *p = (*p) * static_cast<float>(rescaleSlope_) + static_cast<float>(rescaleIntercept_);
+              }
+            }
+          }
+        }
+      }
+    };
+
+    
+    Data  data_;
+
+
+  public:
+    DicomInstanceParameters(const DicomInstanceParameters& other) :
+      data_(other.data_)
+    {
+    }
+
+    DicomInstanceParameters(const Orthanc::DicomMap& dicom) :
+      data_(dicom)
+    {
+    }
+
+    void SetOrthancInstanceIdentifier(const std::string& id)
+    {
+      data_.orthancInstanceId_ = id;
+    }
+
+    const std::string& GetOrthancInstanceIdentifier() const
+    {
+      return data_.orthancInstanceId_;
+    }
+
+    const Orthanc::DicomImageInformation& GetImageInformation() const
+    {
+      return data_.imageInformation_;
+    }
+
+    const std::string& GetStudyInstanceUid() const
+    {
+      return data_.studyInstanceUid_;
+    }
+
+    const std::string& GetSeriesInstanceUid() const
+    {
+      return data_.seriesInstanceUid_;
+    }
+
+    const std::string& GetSopInstanceUid() const
+    {
+      return data_.sopInstanceUid_;
+    }
+
+    OrthancStone::SopClassUid GetSopClassUid() const
+    {
+      return data_.sopClassUid_;
+    }
+
+    double GetThickness() const
+    {
+      return data_.thickness_;
+    }
+
+    double GetPixelSpacingX() const
+    {
+      return data_.pixelSpacingX_;
+    }
+
+    double GetPixelSpacingY() const
+    {
+      return data_.pixelSpacingY_;
+    }
+
+    const OrthancStone::CoordinateSystem3D&  GetGeometry() const
+    {
+      return data_.geometry_;
+    }
+
+    OrthancStone::CoordinateSystem3D  GetFrameGeometry(unsigned int frame) const
+    {
+      return data_.GetFrameGeometry(frame);
+    }
+
+    // TODO - Is this necessary?
+    bool FrameContainsPlane(unsigned int frame,
+                            const OrthancStone::CoordinateSystem3D& plane) const
+    {
+      return data_.FrameContainsPlane(frame, plane);
+    }
+
+    bool IsColor() const
+    {
+      return data_.isColor_;
+    }
+
+    bool HasRescale() const
+    {
+      return data_.hasRescale_;
+    }
+
+    double GetRescaleIntercept() const
+    {
+      if (data_.hasRescale_)
+      {
+        return data_.rescaleIntercept_;
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+    }
+
+    double GetRescaleSlope() const
+    {
+      if (data_.hasRescale_)
+      {
+        return data_.rescaleSlope_;
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+    }
+
+    bool HasDefaultWindowing() const
+    {
+      return data_.hasDefaultWindowing_;
+    }
+
+    float GetDefaultWindowingCenter() const
+    {
+      if (data_.hasDefaultWindowing_)
+      {
+        return data_.defaultWindowingCenter_;
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+    }
+
+    float GetDefaultWindowingWidth() const
+    {
+      if (data_.hasDefaultWindowing_)
+      {
+        return data_.defaultWindowingWidth_;
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+    }
+
+    Orthanc::PixelFormat GetExpectedPixelFormat() const
+    {
+      return data_.expectedPixelFormat_;
+    }
+
+
+    OrthancStone::TextureBaseSceneLayer* CreateTexture(const Orthanc::ImageAccessor& source) const
+    {
+      assert(sizeof(float) == 4);
+
+      Orthanc::PixelFormat sourceFormat = source.GetFormat();
+
+      if (sourceFormat != GetExpectedPixelFormat())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+      }
+
+      if (sourceFormat == Orthanc::PixelFormat_RGB24)
+      {
+        // This is the case of a color image. No conversion has to be done.
+        return new OrthancStone::ColorTextureSceneLayer(source);
+      }
+      else
+      {
+        if (sourceFormat != Orthanc::PixelFormat_Grayscale16 &&
+            sourceFormat != Orthanc::PixelFormat_Grayscale32 &&
+            sourceFormat != Orthanc::PixelFormat_SignedGrayscale16)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+        }
+
+        std::auto_ptr<OrthancStone::FloatTextureSceneLayer> texture;
+        
+        {
+          // This is the case of a grayscale frame. Convert it to Float32.
+          std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
+                                                                     source.GetWidth(), 
+                                                                     source.GetHeight(),
+                                                                     false));
+          Orthanc::ImageProcessing::Convert(*converted, source);
+
+          // Correct rescale slope/intercept if need be
+          data_.ApplyRescale(*converted, (sourceFormat == Orthanc::PixelFormat_Grayscale32));
+
+          texture.reset(new OrthancStone::FloatTextureSceneLayer(*converted));
+        }
+
+        if (data_.hasDefaultWindowing_)
+        {
+          texture->SetCustomWindowing(data_.defaultWindowingCenter_,
+                                      data_.defaultWindowingWidth_);
+        }
+        
+        return texture.release();
+      }
+    }
+  };
+
+
+  class DicomVolumeImage : public boost::noncopyable
+  {
+  private:
+    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
+    std::vector<DicomInstanceParameters*>       slices_;
+    uint64_t                                    revision_;
+    std::vector<uint64_t>                       slicesRevision_;
+    std::vector<unsigned int>                   slicesQuality_;
+
+    void CheckSlice(size_t index,
+                    const DicomInstanceParameters& reference) const
+    {
+      const DicomInstanceParameters& slice = *slices_[index];
+      
+      if (!OrthancStone::GeometryToolbox::IsParallel(
+            reference.GetGeometry().GetNormal(),
+            slice.GetGeometry().GetNormal()))
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
+                                        "A slice in the volume image is not parallel to the others");
+      }
+
+      if (reference.GetExpectedPixelFormat() != slice.GetExpectedPixelFormat())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat,
+                                        "The pixel format changes across the slices of the volume image");
+      }
+
+      if (reference.GetImageInformation().GetWidth() != slice.GetImageInformation().GetWidth() ||
+          reference.GetImageInformation().GetHeight() != slice.GetImageInformation().GetHeight())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize,
+                                        "The width/height of slices are not constant in the volume image");
+      }
+
+      if (!OrthancStone::LinearAlgebra::IsNear(reference.GetPixelSpacingX(), slice.GetPixelSpacingX()) ||
+          !OrthancStone::LinearAlgebra::IsNear(reference.GetPixelSpacingY(), slice.GetPixelSpacingY()))
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
+                                        "The pixel spacing of the slices change across the volume image");
+      }
+    }
+
+    
+    void CheckVolume() const
+    {
+      for (size_t i = 0; i < slices_.size(); i++)
+      {
+        assert(slices_[i] != NULL);
+        if (slices_[i]->GetImageInformation().GetNumberOfFrames() != 1)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
+                                          "This class does not support multi-frame images");
+        }
+      }
+
+      if (slices_.size() != 0)
+      {
+        const DicomInstanceParameters& reference = *slices_[0];
+
+        for (size_t i = 1; i < slices_.size(); i++)
+        {
+          CheckSlice(i, reference);
+        }
+      }
+    }
+
+
+    void Clear()
+    {
+      image_.reset();
+      
+      for (size_t i = 0; i < slices_.size(); i++)
+      {
+        assert(slices_[i] != NULL);
+        delete slices_[i];
+      }
+
+      slices_.clear();
+      slicesRevision_.clear();
+      slicesQuality_.clear();
+    }
+
+
+    void CheckSliceIndex(size_t index) const
+    {
+      assert(slices_.size() == image_->GetDepth() &&
+             slices_.size() == slicesRevision_.size());
+
+      if (!HasGeometry())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+      else if (index >= slices_.size())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      }
+    }
+
+    
+  public:
+    DicomVolumeImage()
+    {
+    }
+
+    ~DicomVolumeImage()
+    {
+      Clear();
+    }
+
+    // WARNING: The payload of "slices" must be of class "DicomInstanceParameters"
+    void SetGeometry(OrthancStone::SlicesSorter& slices)
+    {
+      Clear();
+      
+      if (!slices.Sort())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
+                                        "Cannot sort the 3D slices of a DICOM series");          
+      }
+
+      if (slices.GetSlicesCount() == 0)
+      {
+        // Empty volume
+        image_.reset(new OrthancStone::ImageBuffer3D(Orthanc::PixelFormat_Grayscale8, 0, 0, 0,
+                                                     false /* don't compute range */));
+      }
+      else
+      {
+        slices_.reserve(slices.GetSlicesCount());
+        slicesRevision_.resize(slices.GetSlicesCount(), 0);
+        slicesQuality_.resize(slices.GetSlicesCount(), 0);
+
+        for (size_t i = 0; i < slices.GetSlicesCount(); i++)
+        {
+          const DicomInstanceParameters& slice =
+            dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(i));
+          slices_.push_back(new DicomInstanceParameters(slice));
+        }
+
+        CheckVolume();
+
+        const double spacingZ = slices.ComputeSpacingBetweenSlices();
+        LOG(INFO) << "Computed spacing between slices: " << spacingZ << "mm";
+      
+        const DicomInstanceParameters& parameters = *slices_[0];
+
+        image_.reset(new OrthancStone::ImageBuffer3D(parameters.GetExpectedPixelFormat(),
+                                                     parameters.GetImageInformation().GetWidth(),
+                                                     parameters.GetImageInformation().GetHeight(),
+                                                     slices.GetSlicesCount(), false /* don't compute range */));      
+
+        image_->GetGeometry().SetAxialGeometry(slices.GetSliceGeometry(0));
+        image_->GetGeometry().SetVoxelDimensions(parameters.GetPixelSpacingX(),
+                                                 parameters.GetPixelSpacingY(), spacingZ);
+      }
+      
+      image_->Clear();
+
+      revision_++;
+    }
+
+    uint64_t GetRevision() const
+    {
+      return revision_;
+    }
+
+    bool HasGeometry() const
+    {
+      return (image_.get() != NULL);
+    }
+
+    const OrthancStone::ImageBuffer3D& GetImage() const
+    {
+      if (!HasGeometry())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+      else
+      {
+        return *image_;
+      }
+    }
+
+    size_t GetSlicesCount() const
+    {
+      if (!HasGeometry())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+      else
+      {
+        return slices_.size();
+      }
+    }
+
+    const DicomInstanceParameters& GetSliceParameters(size_t index) const
+    {
+      CheckSliceIndex(index);
+      return *slices_[index];
+    }
+
+    uint64_t GetSliceRevision(size_t index) const
+    {
+      CheckSliceIndex(index);
+      return slicesRevision_[index];
+    }
+
+    void SetSliceContent(size_t index,
+                         const Orthanc::ImageAccessor& image,
+                         unsigned int quality)
+    {
+      CheckSliceIndex(index);
+
+      // If a better image quality is already available, don't update the content
+      if (quality >= slicesQuality_[index])
+      {
+        {
+          OrthancStone::ImageBuffer3D::SliceWriter writer
+            (*image_, OrthancStone::VolumeProjection_Axial, index);
+          Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image);
+        }
+        
+        revision_ ++;
+        slicesRevision_[index] += 1;
+      }
+    }
+  };
+
+
+
+  class IDicomVolumeSource : public boost::noncopyable
+  {
+  public:
+    virtual ~IDicomVolumeSource()
+    {
+    }
+
+    virtual const DicomVolumeImage& GetVolume() const = 0;
+
+    virtual void NotifyAxialSliceAccessed(unsigned int sliceIndex) = 0;
+  };
+  
+  
+
+  class VolumeSeriesOrthancLoader :
+    public OrthancStone::IObserver,
+    public IDicomVolumeSource
+  {
+  private:
+    static const unsigned int LOW_QUALITY = 0;
+    static const unsigned int MIDDLE_QUALITY = 1;
+    static const unsigned int BEST_QUALITY = 2;
+    
+    
+    static unsigned int GetSliceIndexPayload(const OracleCommandWithPayload& command)
+    {
+      return dynamic_cast< const Orthanc::SingleValueObject<unsigned int>& >(command.GetPayload()).GetValue();
+    }
+
+
+    void ScheduleNextSliceDownload()
+    {
+      assert(strategy_.get() != NULL);
+      
+      unsigned int sliceIndex, quality;
+      
+      if (strategy_->GetNext(sliceIndex, quality))
+      {
+        assert(quality <= BEST_QUALITY);
+
+        const DicomInstanceParameters& slice = volume_.GetSliceParameters(sliceIndex);
+          
+        const std::string& instance = slice.GetOrthancInstanceIdentifier();
+        if (instance.empty())
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+        }
+
+        std::auto_ptr<Refactoring::OracleCommandWithPayload> command;
+        
+        if (quality == BEST_QUALITY)
+        {
+          std::auto_ptr<Refactoring::GetOrthancImageCommand> tmp(
+            new Refactoring::GetOrthancImageCommand);
+          tmp->SetHttpHeader("Accept-Encoding", "gzip");
+          tmp->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam)));
+          tmp->SetInstanceUri(instance, slice.GetExpectedPixelFormat());          
+          tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
+          command.reset(tmp.release());
+        }
+        else
+        {
+          std::auto_ptr<Refactoring::GetOrthancWebViewerJpegCommand> tmp(
+            new Refactoring::GetOrthancWebViewerJpegCommand);
+          tmp->SetHttpHeader("Accept-Encoding", "gzip");
+          tmp->SetInstance(instance);
+          tmp->SetQuality((quality == 0 ? 50 : 90));
+          tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
+          command.reset(tmp.release());
+        }
+
+        command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex));
+        oracle_.Schedule(*this, command.release());
+      }
+    }
+
+
+    void LoadGeometry(const OrthancRestApiCommand::SuccessMessage& message)
+    {
+      Json::Value body;
+      message.ParseJsonBody(body);
+      
+      if (body.type() != Json::objectValue)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+      }
+
+      {
+        Json::Value::Members instances = body.getMemberNames();
+
+        OrthancStone::SlicesSorter slices;
+        
+        for (size_t i = 0; i < instances.size(); i++)
+        {
+          Orthanc::DicomMap dicom;
+          dicom.FromDicomAsJson(body[instances[i]]);
+
+          std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom));
+          instance->SetOrthancInstanceIdentifier(instances[i]);
+
+          OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry();
+          slices.AddSlice(geometry, instance.release());
+        }
+
+        volume_.SetGeometry(slices);
+      }
+
+      if (volume_.GetSlicesCount() != 0)
+      {
+        strategy_.reset(new OrthancStone::BasicFetchingStrategy(
+                          new OrthancStone::BasicFetchingItemsSorter(volume_.GetSlicesCount()), BEST_QUALITY));
+
+        for (unsigned int i = 0; i < 4; i++)   // Schedule up to 4 simultaneous downloads (TODO - parameter)
+        {
+          ScheduleNextSliceDownload();
+        }
+      }
+    }
+
+
+    void LoadBestQualitySliceContent(const Refactoring::GetOrthancImageCommand::SuccessMessage& message)
+    {      
+      volume_.SetSliceContent(GetSliceIndexPayload(message.GetOrigin()),
+                              message.GetImage(), BEST_QUALITY);
+
+      ScheduleNextSliceDownload();
+    }
+
+
+    void LoadJpegSliceContent(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
+    {
+      unsigned int quality;
+      
+      switch (message.GetOrigin().GetQuality())
+      {
+        case 50:
+          quality = LOW_QUALITY;
+          break;
+
+        case 90:
+          quality = MIDDLE_QUALITY;
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+      
+      volume_.SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), quality);
+
+      ScheduleNextSliceDownload();
+    }
+
+
+    IOracle&          oracle_;
+    bool              active_;
+    DicomVolumeImage  volume_;
+    
+    std::auto_ptr<OrthancStone::IFetchingStrategy>   strategy_;
+
+  public:
+    VolumeSeriesOrthancLoader(IOracle& oracle,
+                              OrthancStone::IObservable& oracleObservable) :
+      IObserver(oracleObservable.GetBroker()),
+      oracle_(oracle),
+      active_(false)
+    {
+      oracleObservable.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeSeriesOrthancLoader, OrthancRestApiCommand::SuccessMessage>
+        (*this, &VolumeSeriesOrthancLoader::LoadGeometry));
+
+      oracleObservable.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeSeriesOrthancLoader, GetOrthancImageCommand::SuccessMessage>
+        (*this, &VolumeSeriesOrthancLoader::LoadBestQualitySliceContent));
+
+      oracleObservable.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeSeriesOrthancLoader, GetOrthancWebViewerJpegCommand::SuccessMessage>
+        (*this, &VolumeSeriesOrthancLoader::LoadJpegSliceContent));
+    }
+
+    void LoadSeries(const std::string& seriesId)
+    {
+      if (active_)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+
+      active_ = true;
+
+      std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
+      command->SetUri("/series/" + seriesId + "/instances-tags");
+
+      oracle_.Schedule(*this, command.release());
+    }
+    
+
+    virtual const DicomVolumeImage& GetVolume() const
+    {
+      return volume_;
+    }
+
+    
+    virtual void NotifyAxialSliceAccessed(unsigned int sliceIndex)
+    {
+      if (strategy_.get() == NULL)
+      {
+        // Should have called GetVolume().HasGeometry() before
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+      else
+      {
+        strategy_->SetCurrent(sliceIndex);
+      }
+    }
+  };
+
+
+
+#if 0
+  void LoadInstance(const std::string& instanceId)
+  {
+    if (active_)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    active_ = true;
+
+    // Tag "3004-000c" is "Grid Frame Offset Vector", which is
+    // mandatory to read RT DOSE, but is too long to be returned by default
+
+    // TODO => Should be part of a second call if needed
+
+    std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
+    command->SetUri("/instances/" + instanceId + "/tags?ignore-length=3004-000c");
+    command->SetPayload(new LoadInstanceGeometryHandler(*this));
+
+    oracle_.Schedule(*this, command.release());
+  }
+#endif
+
+
+  /*  class VolumeSlicerBase : public IVolumeSlicer
+      {
+      private:
+      OrthancStone::Scene2D&            scene_;
+      int                               layerDepth_;
+      bool                              first_;
+      OrthancStone::CoordinateSystem3D  lastPlane_;
+
+      protected:
+      bool HasViewportPlaneChanged(const OrthancStone::CoordinateSystem3D& plane) const
+      {
+      if (first_ ||
+      !OrthancStone::LinearAlgebra::IsCloseToZero(
+      boost::numeric::ublas::norm_2(lastPlane_.GetNormal() - plane.GetNormal())))
+      {
+      // This is the first rendering, or the plane has not the same orientation
+      return false;
+      }
+      else
+      {
+      double offset1 = lastPlane_.ProjectAlongNormal(plane.GetOrigin());
+      double offset2 = lastPlane_.ProjectAlongNormal(lastPlane_.GetOrigin());
+      return OrthancStone::LinearAlgebra::IsCloseToZero(offset2 - offset1);
+      }
+      }
+
+      void SetLastViewportPlane(const OrthancStone::CoordinateSystem3D& plane)
+      {
+      first_ = false;
+      lastPlane_ = plane;
+      }
+
+      void SetLayer(OrthancStone::ISceneLayer* layer)
+      {
+      scene_.SetLayer(layerDepth_, layer);
+      }
+
+      void DeleteLayer()
+      {
+      scene_.DeleteLayer(layerDepth_);
+      }
+    
+      public:
+      VolumeSlicerBase(OrthancStone::Scene2D& scene,
+      int layerDepth) :
+      scene_(scene),
+      layerDepth_(layerDepth),
+      first_(true)
+      {
+      }
+      };*/
+  
+
+
+  class DicomVolumeMPRSlicer : public IVolumeSlicer
+  {
+  private:
+    bool                            linearInterpolation_;
+    OrthancStone::Scene2D&          scene_;
+    int                             layerDepth_;
+    IDicomVolumeSource&             source_;
+    bool                            first_;
+    OrthancStone::VolumeProjection  lastProjection_;
+    unsigned int                    lastSliceIndex_;
+    uint64_t                        lastSliceRevision_;
+
+  public:
+    DicomVolumeMPRSlicer(OrthancStone::Scene2D& scene,
+                         int layerDepth,
+                         IDicomVolumeSource& source) :
+      linearInterpolation_(false),
+      scene_(scene),
+      layerDepth_(layerDepth),
+      source_(source),
+      first_(true)
+    {
+    }
+
+    void SetLinearInterpolation(bool enabled)
+    {
+      linearInterpolation_ = enabled;
+    }
+
+    bool IsLinearInterpolation() const
+    {
+      return linearInterpolation_;
+    }
+    
+    virtual void SetViewportPlane(const OrthancStone::CoordinateSystem3D& plane)
+    {
+      if (!source_.GetVolume().HasGeometry() ||
+          source_.GetVolume().GetSlicesCount() == 0)
+      {
+        scene_.DeleteLayer(layerDepth_);
+        return;
+      }
+
+      const OrthancStone::VolumeImageGeometry& geometry = source_.GetVolume().GetImage().GetGeometry();
+
+      OrthancStone::VolumeProjection projection;
+      unsigned int sliceIndex;
+      if (!geometry.DetectSlice(projection, sliceIndex, plane))
+      {
+        // The cutting plane is neither axial, nor coronal, nor
+        // sagittal. Could use "VolumeReslicer" here.
+        scene_.DeleteLayer(layerDepth_);
+        return;
+      }
+
+      uint64_t sliceRevision;
+      if (projection == OrthancStone::VolumeProjection_Axial)
+      {
+        sliceRevision = source_.GetVolume().GetSliceRevision(sliceIndex);
+
+        if (first_ ||
+            lastSliceIndex_ != sliceIndex)
+        {
+          // Reorder the prefetching queue
+          source_.NotifyAxialSliceAccessed(sliceIndex);
+        }
+      }
+      else
+      {
+        // For coronal and sagittal projections, we take the global
+        // revision of the volume
+        sliceRevision = source_.GetVolume().GetRevision();
+      }
+
+      if (first_ ||
+          lastProjection_ != projection ||
+          lastSliceIndex_ != sliceIndex ||
+          lastSliceRevision_ != sliceRevision)
+      {
+        // Either the viewport plane, or the content of the slice have not
+        // changed since the last time the layer was set: Update is needed
+
+        first_ = false;
+        lastProjection_ = projection;
+        lastSliceIndex_ = sliceIndex;
+        lastSliceRevision_ = sliceRevision;
+
+        std::auto_ptr<OrthancStone::TextureBaseSceneLayer> texture;
+        
+        {
+          const DicomInstanceParameters& parameters = source_.GetVolume().GetSliceParameters
+            (projection == OrthancStone::VolumeProjection_Axial ? sliceIndex : 0);
+
+          OrthancStone::ImageBuffer3D::SliceReader reader(source_.GetVolume().GetImage(), projection, sliceIndex);
+          texture.reset(parameters.CreateTexture(reader.GetAccessor()));
+        }
+
+        const OrthancStone::CoordinateSystem3D& system = geometry.GetProjectionGeometry(projection);
+
+        double x0, y0, x1, y1;
+        system.ProjectPoint(x0, y0, system.GetOrigin());
+        system.ProjectPoint(x0, y0, system.GetOrigin() + system.GetAxisX());
+        texture->SetOrigin(x0, y0);
+
+        double dx = x1 - x0;
+        double dy = y1 - y0;
+        if (!OrthancStone::LinearAlgebra::IsCloseToZero(dx) ||
+            !OrthancStone::LinearAlgebra::IsCloseToZero(dy))
+        {
+          texture->SetAngle(atan2(dy, dx));
+        }
+        
+        OrthancStone::Vector tmp;
+        geometry.GetVoxelDimensions(projection);
+        texture->SetPixelSpacing(tmp[0], tmp[1]);
+
+        texture->SetLinearInterpolation(linearInterpolation_);
+    
+        scene_.SetLayer(layerDepth_, texture.release());    
+      }
+    }
+  };
+  
+  
+
+
+
   class NativeOracle : public IOracle
   {
   private:
@@ -992,7 +2176,7 @@
 
   public:
     NativeOracle(IMessageEmitter& emitter) :
-    emitter_(emitter),
+      emitter_(emitter),
       state_(State_Setup),
       workers_(4)
     {
@@ -1067,7 +2251,6 @@
   };
 
 
-
   class NativeApplicationContext : public IMessageEmitter
   {
   private:
@@ -1105,8 +2288,8 @@
 
     public:
       ReaderLock(NativeApplicationContext& that) : 
-      that_(that),
-      lock_(that.mutex_)
+        that_(that),
+        lock_(that.mutex_)
       {
       }
     };
@@ -1120,8 +2303,8 @@
 
     public:
       WriterLock(NativeApplicationContext& that) : 
-      that_(that),
-      lock_(that.mutex_)
+        that_(that),
+        lock_(that.mutex_)
       {
       }
 
@@ -1136,638 +2319,6 @@
       }
     };
   };
-
-
-
-  class DicomInstanceParameters :
-    public Orthanc::IDynamicObject  /* to be used as a payload of SlicesSorter */
-  {
-  private:
-    struct Data   // Struct to ease the copy constructor
-    {
-      Orthanc::DicomImageInformation    imageInformation_;
-      OrthancStone::SopClassUid         sopClassUid_;
-      double                            thickness_;
-      double                            pixelSpacingX_;
-      double                            pixelSpacingY_;
-      OrthancStone::CoordinateSystem3D  geometry_;
-      OrthancStone::Vector              frameOffsets_;
-      bool                              isColor_;
-      bool                              hasRescale_;
-      double                            rescaleOffset_;
-      double                            rescaleSlope_;
-      bool                              hasDefaultWindowing_;
-      float                             defaultWindowingCenter_;
-      float                             defaultWindowingWidth_;
-      Orthanc::PixelFormat              expectedPixelFormat_;
-
-      void ComputeDoseOffsets(const Orthanc::DicomMap& dicom)
-      {
-        // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html
-
-        {
-          std::string increment;
-
-          if (dicom.CopyToString(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false))
-          {
-            Orthanc::Toolbox::ToUpperCase(increment);
-            if (increment != "3004,000C")  // This is the "Grid Frame Offset Vector" tag
-            {
-              LOG(ERROR) << "RT-DOSE: Bad value for the \"FrameIncrementPointer\" tag";
-              return;
-            }
-          }
-        }
-
-        if (!OrthancStone::LinearAlgebra::ParseVector(frameOffsets_, dicom, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) ||
-            frameOffsets_.size() < imageInformation_.GetNumberOfFrames())
-        {
-          LOG(ERROR) << "RT-DOSE: No information about the 3D location of some slice(s)";
-          frameOffsets_.clear();
-        }
-        else
-        {
-          if (frameOffsets_.size() >= 2)
-          {
-            thickness_ = frameOffsets_[1] - frameOffsets_[0];
-
-            if (thickness_ < 0)
-            {
-              thickness_ = -thickness_;
-            }
-          }
-        }
-      }
-
-      Data(const Orthanc::DicomMap& dicom) :
-        imageInformation_(dicom)
-      {
-        if (imageInformation_.GetNumberOfFrames() <= 0)
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-        }
-            
-        std::string s;
-        if (!dicom.CopyToString(s, Orthanc::DICOM_TAG_SOP_CLASS_UID, false))
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-        }
-        else
-        {
-          sopClassUid_ = OrthancStone::StringToSopClassUid(s);
-        }
-
-        if (!dicom.ParseDouble(thickness_, Orthanc::DICOM_TAG_SLICE_THICKNESS))
-        {
-          thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
-        }
-
-        OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dicom);
-
-        std::string position, orientation;
-        if (dicom.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) &&
-            dicom.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false))
-        {
-          geometry_ = OrthancStone::CoordinateSystem3D(position, orientation);
-        }
-
-        if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
-        {
-          ComputeDoseOffsets(dicom);
-        }
-
-        isColor_ = (imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome1 &&
-                    imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome2);
-
-        double doseGridScaling;
-
-        if (dicom.ParseDouble(rescaleOffset_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) &&
-            dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE))
-        {
-          hasRescale_ = true;
-        }
-        else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING))
-        {
-          hasRescale_ = true;
-          rescaleOffset_ = 0;
-          rescaleSlope_ = doseGridScaling;
-        }
-        else
-        {
-          hasRescale_ = false;
-        }
-
-        OrthancStone::Vector c, w;
-        if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
-            OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
-            c.size() > 0 && 
-            w.size() > 0)
-        {
-          hasDefaultWindowing_ = true;
-          defaultWindowingCenter_ = static_cast<float>(c[0]);
-          defaultWindowingWidth_ = static_cast<float>(w[0]);
-        }
-        else
-        {
-          hasDefaultWindowing_ = false;
-        }
-
-        if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
-        {
-          switch (imageInformation_.GetBitsStored())
-          {
-            case 16:
-              expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
-              break;
-
-            case 32:
-              expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
-              break;
-
-            default:
-              throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-          } 
-        }
-        else if (isColor_)
-        {
-          expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
-        }
-        else if (imageInformation_.IsSigned())
-        {
-          expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
-        }
-        else
-        {
-          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
-        }
-      }
-
-      OrthancStone::CoordinateSystem3D  GetFrameGeometry(unsigned int frame) const
-      {
-        if (frame == 0)
-        {
-          return geometry_;
-        }
-        else if (frame >= imageInformation_.GetNumberOfFrames())
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-        else if (sopClassUid_ == OrthancStone::SopClassUid_RTDose)
-        {
-          if (frame >= frameOffsets_.size())
-          {
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-          }
-
-          return OrthancStone::CoordinateSystem3D(
-            geometry_.GetOrigin() + frameOffsets_[frame] * geometry_.GetNormal(),
-            geometry_.GetAxisX(),
-            geometry_.GetAxisY());
-        }
-        else
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-        }
-      }
-
-      // TODO - Is this necessary?
-      bool FrameContainsPlane(unsigned int frame,
-                              const OrthancStone::CoordinateSystem3D& plane) const
-      {
-        if (frame >= imageInformation_.GetNumberOfFrames())
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        OrthancStone::CoordinateSystem3D tmp = geometry_;
-
-        if (frame != 0)
-        {
-          tmp = GetFrameGeometry(frame);
-        }
-
-        double distance;
-
-        return (OrthancStone::CoordinateSystem3D::GetDistance(distance, tmp, plane) &&
-                distance <= thickness_ / 2.0);
-      }
-    };
-    
-    Data  data_;
-
-
-  public:
-    DicomInstanceParameters(const DicomInstanceParameters& other) :
-      data_(other.data_)
-    {
-    }
-
-    
-    DicomInstanceParameters(const Orthanc::DicomMap& dicom) :
-      data_(dicom)
-    {
-    }
-
-    const Orthanc::DicomImageInformation& GetImageInformation() const
-    {
-      return data_.imageInformation_;
-    }
-
-    OrthancStone::SopClassUid GetSopClassUid() const
-    {
-      return data_.sopClassUid_;
-    }
-
-    double GetThickness() const
-    {
-      return data_.thickness_;
-    }
-
-    double GetPixelSpacingX() const
-    {
-      return data_.pixelSpacingX_;
-    }
-
-    double GetPixelSpacingY() const
-    {
-      return data_.pixelSpacingY_;
-    }
-
-    const OrthancStone::CoordinateSystem3D&  GetGeometry() const
-    {
-      return data_.geometry_;
-    }
-
-    OrthancStone::CoordinateSystem3D  GetFrameGeometry(unsigned int frame) const
-    {
-      return data_.GetFrameGeometry(frame);
-    }
-
-    // TODO - Is this necessary?
-    bool FrameContainsPlane(unsigned int frame,
-                            const OrthancStone::CoordinateSystem3D& plane) const
-    {
-      return data_.FrameContainsPlane(frame, plane);
-    }
-
-    bool IsColor() const
-    {
-      return data_.isColor_;
-    }
-
-    bool HasRescale() const
-    {
-      return data_.hasRescale_;
-    }
-
-    double GetRescaleOffset() const
-    {
-      if (data_.hasRescale_)
-      {
-        return data_.rescaleOffset_;
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-    }
-
-    double GetRescaleSlope() const
-    {
-      if (data_.hasRescale_)
-      {
-        return data_.rescaleSlope_;
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-    }
-
-    bool HasDefaultWindowing() const
-    {
-      return data_.hasDefaultWindowing_;
-    }
-
-    float GetDefaultWindowingCenter() const
-    {
-      if (data_.hasDefaultWindowing_)
-      {
-        return data_.defaultWindowingCenter_;
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-    }
-
-    float GetDefaultWindowingWidth() const
-    {
-      if (data_.hasDefaultWindowing_)
-      {
-        return data_.defaultWindowingWidth_;
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-    }
-
-    Orthanc::PixelFormat GetExpectedPixelFormat() const
-    {
-      return data_.expectedPixelFormat_;
-    }
-  };
-
-
-  class DicomVolumeImage : public boost::noncopyable
-  {
-  private:
-    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
-    std::vector<DicomInstanceParameters*>       slices_;
-
-    static const DicomInstanceParameters&
-    GetSliceParameters(const OrthancStone::SlicesSorter& slices,
-                       size_t index)
-    {
-      return dynamic_cast<const DicomInstanceParameters&>(slices.GetSlicePayload(index));
-    }
-
-    static void CheckSlice(const OrthancStone::SlicesSorter& slices,
-                           size_t index,
-                           const OrthancStone::CoordinateSystem3D& reference,
-                           const DicomInstanceParameters& a)
-    {
-      const OrthancStone::CoordinateSystem3D& slice = slices.GetSliceGeometry(index);
-      const DicomInstanceParameters& b = GetSliceParameters(slices, index);
-      
-      if (!OrthancStone::GeometryToolbox::IsParallel(reference.GetNormal(), slice.GetNormal()))
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
-                                        "A slice in the volume image is not parallel to the others");
-      }
-
-      if (a.GetExpectedPixelFormat() != b.GetExpectedPixelFormat())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat,
-                                        "The pixel format changes across the slices of the volume image");
-      }
-
-      if (a.GetImageInformation().GetWidth() != b.GetImageInformation().GetWidth() ||
-          a.GetImageInformation().GetHeight() != b.GetImageInformation().GetHeight())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize,
-                                        "The width/height of slices are not constant in the volume image");
-      }
-
-      if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
-          !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
-                                        "The pixel spacing of the slices change across the volume image");
-      }
-    }
-
-    
-    static void CheckVolume(const OrthancStone::SlicesSorter& slices)
-    {
-      for (size_t i = 0; i < slices.GetSlicesCount(); i++)
-      {
-        if (GetSliceParameters(slices, i).GetImageInformation().GetNumberOfFrames() != 1)
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadGeometry,
-                                          "This class does not support multi-frame images");
-        }
-      }
-
-      if (slices.GetSlicesCount() != 0)
-      {
-        const OrthancStone::CoordinateSystem3D& reference = slices.GetSliceGeometry(0);
-        const DicomInstanceParameters& dicom = GetSliceParameters(slices, 0);
-
-        for (size_t i = 1; i < slices.GetSlicesCount(); i++)
-        {
-          CheckSlice(slices, i, reference, dicom);
-        }
-      }
-    }
-
-
-    void Clear()
-    {
-      image_.reset();
-      
-      for (size_t i = 0; i < slices_.size(); i++)
-      {
-        assert(slices_[i] != NULL);
-        delete slices_[i];
-      }
-    }
-
-    
-  public:
-    DicomVolumeImage()
-    {
-    }
-
-    ~DicomVolumeImage()
-    {
-      Clear();
-    }
-
-    // WARNING: The payload of "slices" must be of class "DicomInstanceParameters"
-    void SetGeometry(OrthancStone::SlicesSorter& slices)
-    {
-      Clear();
-      
-      if (!slices.Sort())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
-                                        "Cannot sort the 3D slices of a DICOM series");          
-      }
-
-      slices_.reserve(slices.GetSlicesCount());
-
-      for (size_t i = 0; i < slices.GetSlicesCount(); i++)
-      {
-        slices_.push_back(new DicomInstanceParameters(GetSliceParameters(slices, i)));
-      }
-
-      CheckVolume(slices);
-
-      const double spacingZ = slices.ComputeSpacingBetweenSlices();
-      LOG(INFO) << "Computed spacing between slices: " << spacingZ << "mm";
-      
-      const DicomInstanceParameters& parameters = GetSliceParameters(slices, 0);
-
-      image_.reset(new OrthancStone::ImageBuffer3D(parameters.GetExpectedPixelFormat(),
-                                                   parameters.GetImageInformation().GetWidth(),
-                                                   parameters.GetImageInformation().GetHeight(),
-                                                   slices.GetSlicesCount(), false /* don't compute range */));      
-
-      image_->SetAxialGeometry(slices.GetSliceGeometry(0));
-      image_->SetVoxelDimensions(parameters.GetPixelSpacingX(), parameters.GetPixelSpacingY(), spacingZ);
-      image_->Clear();
-    }
-
-    bool IsGeometryReady() const
-    {
-      return (image_.get() != NULL);
-    }
-
-    const OrthancStone::ImageBuffer3D& GetImage() const
-    {
-      if (!IsGeometryReady())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        return *image_;
-      }
-    }      
-  };
-  
-  
-
-  class AxialVolumeOrthancLoader : public OrthancStone::IObserver
-  {
-  private:
-    class MessageHandler : public Orthanc::IDynamicObject
-    {
-    public:
-      virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const = 0;
-    };
-
-    void Handle(const OrthancRestApiCommand::SuccessMessage& message)
-    {
-      dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message);
-    }
-
-
-    class LoadSeriesGeometryHandler : public MessageHandler
-    {
-    private:
-      AxialVolumeOrthancLoader&  that_;
-
-    public:
-      LoadSeriesGeometryHandler(AxialVolumeOrthancLoader& that) :
-      that_(that)
-      {
-      }
-
-      virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
-      {
-        Json::Value value;
-        message.ParseJsonBody(value);
-
-        if (value.type() != Json::objectValue)
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
-        }
-
-        Json::Value::Members instances = value.getMemberNames();
-
-        OrthancStone::SlicesSorter slices;
-        
-        for (size_t i = 0; i < instances.size(); i++)
-        {
-          Orthanc::DicomMap dicom;
-          dicom.FromDicomAsJson(value[instances[i]]);
-
-          std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom));
-
-          OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry();
-          slices.AddSlice(geometry, instance.release());
-        }
-
-        that_.image_.SetGeometry(slices);
-      }
-    };
-
-
-    class LoadInstanceGeometryHandler : public MessageHandler
-    {
-    private:
-      AxialVolumeOrthancLoader&  that_;
-
-    public:
-      LoadInstanceGeometryHandler(AxialVolumeOrthancLoader& that) :
-      that_(that)
-      {
-      }
-
-      virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
-      {
-        Json::Value value;
-        message.ParseJsonBody(value);
-
-        if (value.type() != Json::objectValue)
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
-        }
-
-        Orthanc::DicomMap dicom;
-        dicom.FromDicomAsJson(value);
-
-        DicomInstanceParameters instance(dicom);
-      }
-    };
-
-
-    bool              active_;
-    DicomVolumeImage  image_;
-
-  public:
-    AxialVolumeOrthancLoader(OrthancStone::IObservable& oracle) :
-      IObserver(oracle.GetBroker()),
-      active_(false)
-    {
-      oracle.RegisterObserverCallback(
-        new OrthancStone::Callable<AxialVolumeOrthancLoader, OrthancRestApiCommand::SuccessMessage>
-        (*this, &AxialVolumeOrthancLoader::Handle));
-    }
-
-    void LoadSeries(IOracle& oracle,
-                    const std::string& seriesId)
-    {
-      if (active_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-
-      active_ = true;
-
-      std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
-      command->SetUri("/series/" + seriesId + "/instances-tags");
-      command->SetPayload(new LoadSeriesGeometryHandler(*this));
-
-      oracle.Schedule(*this, command.release());
-    }
-
-    void LoadInstance(IOracle& oracle,
-                      const std::string& instanceId)
-    {
-      if (active_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-
-      active_ = true;
-
-      // Tag "3004-000c" is "Grid Frame Offset Vector", which is
-      // mandatory to read RT DOSE, but is too long to be returned by default
-
-      // TODO => Should be part of a second call if needed
-
-      std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand);
-      command->SetUri("/instances/" + instanceId + "/tags?ignore-length=3004-000c");
-      command->SetPayload(new LoadInstanceGeometryHandler(*this));
-
-      oracle.Schedule(*this, command.release());
-    }
-  };
-
 }
 
 
@@ -1823,7 +2374,7 @@
 
     oracle.RegisterObserverCallback
       (new OrthancStone::Callable
-      <Toto, Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle));
+       <Toto, Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle));
 
     oracle.RegisterObserverCallback
       (new OrthancStone::Callable
@@ -1832,29 +2383,19 @@
 };
 
 
-void Run(Refactoring::NativeApplicationContext& context)
+void Run(Refactoring::NativeApplicationContext& context,
+         Refactoring::IOracle& oracle)
 {
   std::auto_ptr<Toto> toto;
-  std::auto_ptr<Refactoring::AxialVolumeOrthancLoader> loader1, loader2;
+  std::auto_ptr<Refactoring::VolumeSeriesOrthancLoader> loader1, loader2;
 
   {
     Refactoring::NativeApplicationContext::WriterLock lock(context);
     toto.reset(new Toto(lock.GetOracleObservable()));
-    loader1.reset(new Refactoring::AxialVolumeOrthancLoader(lock.GetOracleObservable()));
-    loader2.reset(new Refactoring::AxialVolumeOrthancLoader(lock.GetOracleObservable()));
+    loader1.reset(new Refactoring::VolumeSeriesOrthancLoader(oracle, lock.GetOracleObservable()));
+    loader2.reset(new Refactoring::VolumeSeriesOrthancLoader(oracle, lock.GetOracleObservable()));
   }
 
-  Refactoring::NativeOracle oracle(context);
-
-  {
-    Orthanc::WebServiceParameters p;
-    //p.SetUrl("http://localhost:8043/");
-    p.SetCredentials("orthanc", "orthanc");
-    oracle.SetOrthancParameters(p);
-  }
-
-  oracle.Start();
-
   if (1)
   {
     Json::Value v = Json::objectValue;
@@ -1921,17 +2462,15 @@
 
 
   // 2017-11-17-Anonymized
-  //loader1->LoadSeries(oracle, "cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618");  // CT
-  loader2->LoadInstance(oracle, "41029085-71718346-811efac4-420e2c15-d39f99b6");  // RT-DOSE
+  //loader1->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618");  // CT
+  //loader2->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6");  // RT-DOSE
 
   // Delphine
-  loader1->LoadSeries(oracle, "5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e");  // CT
+  loader1->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e");  // CT
 
   LOG(WARNING) << "...Waiting for Ctrl-C...";
   Orthanc::SystemToolbox::ServerBarrier();
   //boost::this_thread::sleep(boost::posix_time::seconds(1));
-
-  oracle.Stop();
 }
 
 
@@ -1949,7 +2488,21 @@
   try
   {
     Refactoring::NativeApplicationContext context;
-    Run(context);
+
+    Refactoring::NativeOracle oracle(context);
+
+    {
+      Orthanc::WebServiceParameters p;
+      //p.SetUrl("http://localhost:8043/");
+      p.SetCredentials("orthanc", "orthanc");
+      oracle.SetOrthancParameters(p);
+    }
+
+    oracle.Start();
+
+    Run(context, oracle);
+
+    oracle.Stop();
   }
   catch (Orthanc::OrthancException& e)
   {
--- a/Samples/Sdl/TrackerSampleApp.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/Samples/Sdl/TrackerSampleApp.cpp	Tue May 21 13:25:58 2019 +0200
@@ -20,21 +20,22 @@
 
 #include "TrackerSampleApp.h"
 
-#include "../Common/CreateLineMeasureTracker.h"
-#include "../Common/CreateAngleMeasureTracker.h"
-
-#include "../../Applications/Sdl/SdlOpenGLWindow.h"
+#include <Framework/Scene2DViewport/CreateLineMeasureTracker.h>
+#include <Framework/Scene2DViewport/CreateAngleMeasureTracker.h>
 
-#include "../../Framework/Scene2D/PanSceneTracker.h"
-#include "../../Framework/Scene2D/RotateSceneTracker.h"
-#include "../../Framework/Scene2D/Scene2D.h"
-#include "../../Framework/Scene2D/ZoomSceneTracker.h"
-#include "../../Framework/Scene2D/CairoCompositor.h"
-#include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
-#include "../../Framework/Scene2D/OpenGLCompositor.h"
-#include "../../Framework/StoneInitialization.h"
+#include <Framework/Scene2D/PanSceneTracker.h>
+#include <Framework/Scene2D/RotateSceneTracker.h>
+#include <Framework/Scene2D/Scene2D.h>
+#include <Framework/Scene2D/ZoomSceneTracker.h>
+#include <Framework/Scene2D/CairoCompositor.h>
+#include <Framework/Scene2D/ColorTextureSceneLayer.h>
+#include <Framework/Scene2D/OpenGLCompositor.h>
 
- // From Orthanc framework
+#include <Framework/StoneInitialization.h>
+
+#include <Applications/Sdl/SdlOpenGLWindow.h>
+
+// From Orthanc framework
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
 #include <Core/Images/Image.h>
@@ -67,9 +68,9 @@
     return descs[i];
   }
 
-  Scene2D& TrackerSampleApp::GetScene()
+  Scene2DPtr TrackerSampleApp::GetScene()
   {
-    return scene_;
+    return controller_->GetScene();
   }
 
   void TrackerSampleApp::SelectNextTool()
@@ -87,17 +88,19 @@
       return;
 
     std::stringstream msg;
-    for (auto kv : infoTextMap_)
+	
+	for (std::map<std::string, std::string>::const_iterator kv = infoTextMap_.begin();
+		kv != infoTextMap_.end(); ++kv)
     {
-      msg << kv.first << " : " << kv.second << std::endl;
+      msg << kv->first << " : " << kv->second << std::endl;
     }
-    auto msgS = msg.str();
+	std::string msgS = msg.str();
 
     TextSceneLayer* layerP = NULL;
-    if (scene_.HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX))
+    if (GetScene()->HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX))
     {
       TextSceneLayer& layer = dynamic_cast<TextSceneLayer&>(
-        scene_.GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX));
+        GetScene()->GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX));
       layerP = &layer;
     }
     else
@@ -109,29 +112,29 @@
       layer->SetBorder(20);
       layer->SetAnchor(BitmapAnchor_TopLeft);
       //layer->SetPosition(0,0);
-      scene_.SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release());
+      GetScene()->SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release());
     }
     // position the fixed info text in the upper right corner
     layerP->SetText(msgS.c_str());
     double cX = compositor_->GetCanvasWidth() * (-0.5);
     double cY = compositor_->GetCanvasHeight() * (-0.5);
-    scene_.GetCanvasToSceneTransform().Apply(cX,cY);
+    GetScene()->GetCanvasToSceneTransform().Apply(cX,cY);
     layerP->SetPosition(cX, cY);
   }
 
   void TrackerSampleApp::DisplayFloatingCtrlInfoText(const PointerEvent& e)
   {
-    ScenePoint2D p = e.GetMainPosition().Apply(scene_.GetCanvasToSceneTransform());
+    ScenePoint2D p = e.GetMainPosition().Apply(GetScene()->GetCanvasToSceneTransform());
 
     char buf[128];
     sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)", 
       p.GetX(), p.GetY(), 
       e.GetMainPosition().GetX(), e.GetMainPosition().GetY());
 
-    if (scene_.HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX))
+    if (GetScene()->HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX))
     {
       TextSceneLayer& layer =
-        dynamic_cast<TextSceneLayer&>(scene_.GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX));
+        dynamic_cast<TextSceneLayer&>(GetScene()->GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX));
       layer.SetText(buf);
       layer.SetPosition(p.GetX(), p.GetY());
     }
@@ -143,13 +146,13 @@
       layer->SetBorder(20);
       layer->SetAnchor(BitmapAnchor_BottomCenter);
       layer->SetPosition(p.GetX(), p.GetY());
-      scene_.SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release());
+      GetScene()->SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release());
     }
   }
 
   void TrackerSampleApp::HideInfoText()
   {
-    scene_.DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX);
+    GetScene()->DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX);
   }
 
   void TrackerSampleApp::HandleApplicationEvent(
@@ -191,8 +194,8 @@
           //  e.GetMainPosition().GetX() << " " << e.GetMainPosition().GetY();
           
           activeTracker_->PointerMove(e);
-          if (!activeTracker_->IsActive())
-            activeTracker_ = NULL;
+          if (!activeTracker_->IsAlive())
+            activeTracker_.reset();
         }
       }
     }
@@ -203,8 +206,8 @@
         PointerEvent e;
         e.AddPosition(compositor_->GetPixelCenterCoordinates(event.button.x, event.button.y));
         activeTracker_->PointerUp(e);
-        if (!activeTracker_->IsActive())
-          activeTracker_ = NULL;
+        if (!activeTracker_->IsAlive())
+          activeTracker_.reset();
       }
     }
     else if (event.type == SDL_MOUSEBUTTONDOWN)
@@ -215,8 +218,8 @@
       if (activeTracker_)
       {
         activeTracker_->PointerDown(e);
-        if (!activeTracker_->IsActive())
-          activeTracker_ = NULL;
+        if (!activeTracker_->IsAlive())
+          activeTracker_.reset();
       }
       else
       {
@@ -233,8 +236,8 @@
         if (activeTracker_)
         {
           activeTracker_->Cancel();
-          if (!activeTracker_->IsActive())
-            activeTracker_ = NULL;
+          if (!activeTracker_->IsAlive())
+            activeTracker_.reset();
         }
         break;
 
@@ -249,7 +252,7 @@
         break;
 
       case SDLK_s:
-        scene_.FitContent(compositor_->GetCanvasWidth(),
+        controller_->FitContent(compositor_->GetCanvasWidth(),
           compositor_->GetCanvasHeight());
         break;
 
@@ -267,7 +270,8 @@
   }
 
 
-  void TrackerSampleApp::OnSceneTransformChanged(const Scene2D::SceneTransformChanged& message)
+  void TrackerSampleApp::OnSceneTransformChanged(
+    const ViewportController::SceneTransformChanged& message)
   {
     DisplayInfoText();
   }
@@ -279,12 +283,12 @@
     switch (event.button.button)
     {
     case SDL_BUTTON_MIDDLE:
-      return CreateSimpleTrackerAdapter(PointerTrackerPtr(
-        new PanSceneTracker(scene_, e)));
+      return FlexiblePointerTrackerPtr(new PanSceneTracker
+        (controller_, e));
 
     case SDL_BUTTON_RIGHT:
-      return CreateSimpleTrackerAdapter(PointerTrackerPtr(
-        new ZoomSceneTracker(scene_, e, compositor_->GetCanvasHeight())));
+      return FlexiblePointerTrackerPtr(new ZoomSceneTracker
+        (controller_, e, compositor_->GetCanvasHeight()));
 
     case SDL_BUTTON_LEFT:
     {
@@ -309,50 +313,50 @@
         {
         case GuiTool_Rotate:
           //LOG(TRACE) << "Creating RotateSceneTracker";
-          return CreateSimpleTrackerAdapter(PointerTrackerPtr(
-            new RotateSceneTracker(scene_, e)));
+          return FlexiblePointerTrackerPtr(new RotateSceneTracker(
+            controller_, e));
         case GuiTool_Pan:
-          return CreateSimpleTrackerAdapter(PointerTrackerPtr(
-            new PanSceneTracker(scene_, e)));
+          return FlexiblePointerTrackerPtr(new PanSceneTracker(
+            controller_, e));
         case GuiTool_Zoom:
-          return CreateSimpleTrackerAdapter(PointerTrackerPtr(
-            new ZoomSceneTracker(scene_, e, compositor_->GetCanvasHeight())));
+          return FlexiblePointerTrackerPtr(new ZoomSceneTracker(
+            controller_, e, compositor_->GetCanvasHeight()));
         //case GuiTool_AngleMeasure:
-        //  return new AngleMeasureTracker(scene_, measureTools_, undoStack_, e);
+        //  return new AngleMeasureTracker(GetScene(), e);
         //case GuiTool_CircleMeasure:
-        //  return new CircleMeasureTracker(scene_, measureTools_, undoStack_, e);
+        //  return new CircleMeasureTracker(GetScene(), e);
         //case GuiTool_EllipseMeasure:
-        //  return new EllipseMeasureTracker(scene_, measureTools_, undoStack_, e);
+        //  return new EllipseMeasureTracker(GetScene(), e);
         case GuiTool_LineMeasure:
           return FlexiblePointerTrackerPtr(new CreateLineMeasureTracker(
-            IObserver::GetBroker(), scene_, undoStack_, measureTools_, e));
+            IObserver::GetBroker(), controller_, e));
         case GuiTool_AngleMeasure:
           return FlexiblePointerTrackerPtr(new CreateAngleMeasureTracker(
-            IObserver::GetBroker(), scene_, undoStack_, measureTools_, e));
-          return NULL;
+            IObserver::GetBroker(), controller_, e));
         case GuiTool_CircleMeasure:
           LOG(ERROR) << "Not implemented yet!";
-          return NULL;
+          return FlexiblePointerTrackerPtr();
         case GuiTool_EllipseMeasure:
           LOG(ERROR) << "Not implemented yet!";
-          return NULL;
+          return FlexiblePointerTrackerPtr();
         default:
           throw OrthancException(ErrorCode_InternalError, "Wrong tool!");
         }
       }
     }
     default:
-      return NULL;
+      return FlexiblePointerTrackerPtr();
     }
   }
 
 
   TrackerSampleApp::TrackerSampleApp(MessageBroker& broker) : IObserver(broker)
-    , scene_(broker)
     , currentTool_(GuiTool_Rotate)
   {
-    scene_.RegisterObserverCallback(
-      new Callable<TrackerSampleApp, Scene2D::SceneTransformChanged>
+    controller_ = ViewportControllerPtr(new ViewportController(broker));
+
+    controller_->RegisterObserverCallback(
+      new Callable<TrackerSampleApp, ViewportController::SceneTransformChanged>
       (*this, &TrackerSampleApp::OnSceneTransformChanged));
 
     TEXTURE_2x2_1_ZINDEX = 1;
@@ -362,8 +366,6 @@
     LINESET_2_ZINDEX = 5;
     FLOATING_INFOTEXT_LAYER_ZINDEX = 6;
     FIXED_INFOTEXT_LAYER_ZINDEX = 7;
-
-
   }
 
   void TrackerSampleApp::PrepareScene()
@@ -390,13 +392,13 @@
       p[4] = 0;
       p[5] = 0;
 
-      scene_.SetLayer(TEXTURE_2x2_1_ZINDEX, new ColorTextureSceneLayer(i));
+      GetScene()->SetLayer(TEXTURE_2x2_1_ZINDEX, new ColorTextureSceneLayer(i));
 
       std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
       l->SetOrigin(-3, 2);
       l->SetPixelSpacing(1.5, 1);
       l->SetAngle(20.0 / 180.0 * M_PI);
-      scene_.SetLayer(TEXTURE_2x2_2_ZINDEX, l.release());
+      GetScene()->SetLayer(TEXTURE_2x2_2_ZINDEX, l.release());
     }
 
     // Texture of 1x1 size
@@ -411,7 +413,7 @@
       std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
       l->SetOrigin(-2, 1);
       l->SetAngle(20.0 / 180.0 * M_PI);
-      scene_.SetLayer(TEXTURE_1x1_ZINDEX, l.release());
+      GetScene()->SetLayer(TEXTURE_1x1_ZINDEX, l.release());
     }
 
     // Some lines
@@ -443,14 +445,14 @@
       layer->AddChain(chain, false);
 
       layer->SetColor(0, 255, 255);
-      scene_.SetLayer(LINESET_1_ZINDEX, layer.release());
+      GetScene()->SetLayer(LINESET_1_ZINDEX, layer.release());
     }
 
     // Some text
     {
       std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer);
       layer->SetText("Hello");
-      scene_.SetLayer(LINESET_2_ZINDEX, layer.release());
+      GetScene()->SetLayer(LINESET_2_ZINDEX, layer.release());
     }
   }
 
@@ -460,7 +462,7 @@
     if (activeTracker_)
     {
       activeTracker_->Cancel();
-      activeTracker_ = NULL;
+      activeTracker_.reset();
     }
   }
 
@@ -468,7 +470,7 @@
     unsigned int canvasWidth,
     unsigned int canvasHeight)
   {
-    CairoCompositor compositor(scene_, canvasWidth, canvasHeight);
+    CairoCompositor compositor(*GetScene(), canvasWidth, canvasHeight);
     compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE_0, Orthanc::Encoding_Latin1);
     compositor.Refresh();
 
@@ -486,7 +488,7 @@
   FlexiblePointerTrackerPtr TrackerSampleApp::TrackerHitTest(const PointerEvent & e)
   {
     // std::vector<MeasureToolPtr> measureTools_;
-    return nullptr;
+    return FlexiblePointerTrackerPtr();
   }
 
   static void GLAPIENTRY
@@ -514,12 +516,12 @@
     // that needs to be scaled
     SdlOpenGLWindow window("Hello", 1024, 1024, false);
 
-    GetScene().FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
+    controller_->FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
 
     glEnable(GL_DEBUG_OUTPUT);
     glDebugMessageCallback(OpenGLMessageCallback, 0);
 
-    compositor_.reset(new OpenGLCompositor(window, GetScene()));
+    compositor_.reset(new OpenGLCompositor(window, *GetScene()));
 
     compositor_->SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
       FONT_SIZE_0, Orthanc::Encoding_Latin1);
@@ -564,6 +566,9 @@
       }
       SDL_Delay(1);
     }
+
+    // the following is paramount because the compositor holds a reference
+    // to the scene and we do not want this reference to become dangling
     compositor_.reset(NULL);
   }
 
--- a/Samples/Sdl/TrackerSampleApp.h	Thu May 16 19:10:38 2019 +0200
+++ b/Samples/Sdl/TrackerSampleApp.h	Tue May 21 13:25:58 2019 +0200
@@ -18,11 +18,15 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
 
-#include <Framework/Scene2D/OpenGLCompositor.h>
+#include <Framework/Scene2DViewport/PointerTypes.h>
+
 #include <Framework/Messages/IObserver.h>
 
-#include "../Common/IFlexiblePointerTracker.h"
-#include "../Common/MeasureTools.h"
+#include <Framework/Scene2D/OpenGLCompositor.h>
+
+#include <Framework/Scene2DViewport/ViewportController.h>
+#include <Framework/Scene2DViewport/IFlexiblePointerTracker.h>
+#include <Framework/Scene2DViewport/MeasureTools.h>
 
 #include <SDL.h>
 
@@ -32,9 +36,6 @@
 
 namespace OrthancStone
 {
-  class TrackerCommand;
-  typedef boost::shared_ptr<TrackerCommand> TrackerCommandPtr;
-
   enum GuiTool
   {
     GuiTool_Rotate = 0,
@@ -65,7 +66,7 @@
     void SetInfoDisplayMessage(std::string key, std::string value);
     void DisableTracker();
 
-    Scene2D& GetScene();
+    Scene2DPtr GetScene();
 
     void HandleApplicationEvent(const SDL_Event& event);
 
@@ -73,7 +74,8 @@
     This method is called when the scene transform changes. It allows to
     recompute the visual elements whose content depend upon the scene transform
     */
-    void OnSceneTransformChanged(const Scene2D::SceneTransformChanged& message);
+    void OnSceneTransformChanged(
+      const ViewportController::SceneTransformChanged& message);
 
   private:
     void SelectNextTool();
@@ -108,18 +110,13 @@
     WARNING: the measuring tools do store a reference to the scene, and it 
     paramount that the scene gets destroyed AFTER the measurement tools.
     */
-    Scene2D scene_;
+    ViewportControllerPtr controller_;
 
     std::map<std::string, std::string> infoTextMap_;
     FlexiblePointerTrackerPtr activeTracker_;
-    std::vector<TrackerCommandPtr> undoStack_;
-
-    // we store the measure tools here so that they don't get deleted
-    std::vector<MeasureToolPtr> measureTools_;
 
     //static const int LAYER_POSITION = 150;
 
-
     int TEXTURE_2x2_1_ZINDEX;
     int TEXTURE_1x1_ZINDEX;
     int TEXTURE_2x2_2_ZINDEX;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/TestStrategy.cpp	Tue May 21 13:25:58 2019 +0200
@@ -0,0 +1,391 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "gtest/gtest.h"
+
+#include "../Framework/Loaders/BasicFetchingStrategy.h"
+#include "../Framework/Loaders/BasicFetchingItemsSorter.h"
+
+#include <Core/OrthancException.h>
+
+
+namespace
+{
+  class StrategyTester : public boost::noncopyable
+  {
+  private:
+    std::map<unsigned int, unsigned int>  qualities_;
+
+  public:
+    bool IsValidCommand(unsigned int item,
+                        unsigned int quality)
+    {
+      if (qualities_.find(item) != qualities_.end() &&
+          qualities_[item] >= quality)
+      {
+        return false;
+      }
+      else
+      {
+        qualities_[item] = quality;
+        return true;
+      }
+    }
+
+    bool HasFinished(OrthancStone::BasicFetchingStrategy& strategy)
+    {
+      for (unsigned int i = 0; i < strategy.GetItemsCount(); i++)
+      {
+        if (qualities_.find(i) == qualities_.end() ||
+            qualities_[i] != strategy.GetMaxQuality())
+        {
+          return false;
+        }
+      }
+
+      return true;
+    }
+  };
+}
+
+
+TEST(BasicFetchingStrategy, Test1)
+{
+  ASSERT_THROW(OrthancStone::BasicFetchingStrategy(NULL, 0), Orthanc::OrthancException);
+  ASSERT_THROW(OrthancStone::BasicFetchingStrategy(new OrthancStone::BasicFetchingItemsSorter(0), 0), Orthanc::OrthancException);
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(1), 0);
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(0u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(1), 5);
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(5u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(2), 2);
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(2u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(1u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(2u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(3), 2);
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(2u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(1u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(1u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(2u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(2u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(3), 2);
+    s.SetBlockSize(1);
+    s.SetCurrent(0);
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(2u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(1u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(2u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(1u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(2u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(5), 0);
+    ASSERT_THROW(s.SetCurrent(5), Orthanc::OrthancException);
+    s.SetCurrent(2);
+
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(3u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(4u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(0u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+
+  {
+    OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(5), 0);
+    s.SetCurrent(4);
+
+    unsigned int i, q;
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(4u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(3u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(2u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(1u, i);  ASSERT_EQ(0u, q);
+    ASSERT_TRUE(s.GetNext(i, q));   ASSERT_EQ(0u, i);  ASSERT_EQ(0u, q);
+    ASSERT_FALSE(s.GetNext(i, q));
+  }
+}
+
+
+TEST(BasicFetchingStrategy, Test2)
+{
+  OrthancStone::BasicFetchingStrategy s(new OrthancStone::BasicFetchingItemsSorter(20), 2);
+  ASSERT_EQ(20u, s.GetItemsCount());
+  ASSERT_EQ(2u, s.GetMaxQuality());
+
+  StrategyTester t;
+
+  s.SetCurrent(10);
+
+  unsigned int i, q;
+  while (s.GetNext(i, q))
+  {
+    ASSERT_TRUE(t.IsValidCommand(i, q));
+  }
+
+  ASSERT_TRUE(t.HasFinished(s));
+}
+
+
+
+
+TEST(BasicFetchingItemsSorter, Small)
+{
+  ASSERT_THROW(OrthancStone::BasicFetchingItemsSorter(0), Orthanc::OrthancException);
+  std::vector<unsigned int> v;
+
+  {
+    OrthancStone::BasicFetchingItemsSorter s(1);
+    s.Sort(v, 0);
+    ASSERT_EQ(1u, v.size());
+    ASSERT_EQ(0u, v[0]);
+
+    ASSERT_THROW(s.Sort(v, 1), Orthanc::OrthancException);
+  }
+
+  {
+    OrthancStone::BasicFetchingItemsSorter s(2);
+    s.Sort(v, 0);
+    ASSERT_EQ(2u, v.size());
+    ASSERT_EQ(0u, v[0]);
+    ASSERT_EQ(1u, v[1]);
+
+    s.Sort(v, 1);
+    ASSERT_EQ(2u, v.size());
+    ASSERT_EQ(1u, v[0]);
+    ASSERT_EQ(0u, v[1]);
+
+    ASSERT_THROW(s.Sort(v, 2), Orthanc::OrthancException);
+  }
+
+  {
+    OrthancStone::BasicFetchingItemsSorter s(3);
+    s.Sort(v, 0);
+    ASSERT_EQ(3u, v.size());
+    ASSERT_EQ(0u, v[0]);
+    ASSERT_EQ(1u, v[1]);
+    ASSERT_EQ(2u, v[2]);
+    
+    s.Sort(v, 1);
+    ASSERT_EQ(3u, v.size());
+    ASSERT_EQ(1u, v[0]);
+    ASSERT_EQ(2u, v[1]);
+    ASSERT_EQ(0u, v[2]);
+    
+    s.Sort(v, 2);
+    ASSERT_EQ(3u, v.size());
+    ASSERT_EQ(2u, v[0]);
+    ASSERT_EQ(1u, v[1]);
+    ASSERT_EQ(0u, v[2]);
+    
+    ASSERT_THROW(s.Sort(v, 3), Orthanc::OrthancException);
+  }
+}
+
+
+TEST(BasicFetchingItemsSorter, Odd)
+{
+  OrthancStone::BasicFetchingItemsSorter s(7);
+  std::vector<unsigned int> v;
+
+  ASSERT_THROW(s.Sort(v, 7), Orthanc::OrthancException);
+
+  {
+    s.Sort(v, 0);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(0u, v[0]);
+    ASSERT_EQ(1u, v[1]);
+    ASSERT_EQ(2u, v[2]);
+    ASSERT_EQ(3u, v[3]);
+    ASSERT_EQ(4u, v[4]);
+    ASSERT_EQ(5u, v[5]);
+    ASSERT_EQ(6u, v[6]);
+  }
+
+  {
+    s.Sort(v, 1);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(1u, v[0]);
+    ASSERT_EQ(2u, v[1]);
+    ASSERT_EQ(0u, v[2]);
+    ASSERT_EQ(3u, v[3]);
+    ASSERT_EQ(4u, v[4]);
+    ASSERT_EQ(5u, v[5]);
+    ASSERT_EQ(6u, v[6]);
+  }
+
+  {
+    s.Sort(v, 2);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(2u, v[0]);
+    ASSERT_EQ(3u, v[1]);
+    ASSERT_EQ(1u, v[2]);
+    ASSERT_EQ(4u, v[3]);
+    ASSERT_EQ(0u, v[4]);
+    ASSERT_EQ(5u, v[5]);
+    ASSERT_EQ(6u, v[6]);
+  }
+
+  {
+    s.Sort(v, 3);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(3u, v[0]);
+    ASSERT_EQ(4u, v[1]);
+    ASSERT_EQ(2u, v[2]);
+    ASSERT_EQ(5u, v[3]);
+    ASSERT_EQ(1u, v[4]);
+    ASSERT_EQ(6u, v[5]);
+    ASSERT_EQ(0u, v[6]);
+  }
+
+  {
+    s.Sort(v, 4);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(4u, v[0]);
+    ASSERT_EQ(5u, v[1]);
+    ASSERT_EQ(3u, v[2]);
+    ASSERT_EQ(6u, v[3]);
+    ASSERT_EQ(2u, v[4]);
+    ASSERT_EQ(1u, v[5]);
+    ASSERT_EQ(0u, v[6]);
+  }
+
+  {
+    s.Sort(v, 5);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(5u, v[0]);
+    ASSERT_EQ(6u, v[1]);
+    ASSERT_EQ(4u, v[2]);
+    ASSERT_EQ(3u, v[3]);
+    ASSERT_EQ(2u, v[4]);
+    ASSERT_EQ(1u, v[5]);
+    ASSERT_EQ(0u, v[6]);
+  }
+
+  {
+    s.Sort(v, 6);
+    ASSERT_EQ(7u, v.size());
+    ASSERT_EQ(6u, v[0]);
+    ASSERT_EQ(5u, v[1]);
+    ASSERT_EQ(4u, v[2]);
+    ASSERT_EQ(3u, v[3]);
+    ASSERT_EQ(2u, v[4]);
+    ASSERT_EQ(1u, v[5]);
+    ASSERT_EQ(0u, v[6]);
+  }
+}
+
+
+TEST(BasicFetchingItemsSorter, Even)
+{
+  OrthancStone::BasicFetchingItemsSorter s(6);
+  std::vector<unsigned int> v;
+
+  {
+    s.Sort(v, 0);
+    ASSERT_EQ(6u, v.size());
+    ASSERT_EQ(0u, v[0]);
+    ASSERT_EQ(1u, v[1]);
+    ASSERT_EQ(2u, v[2]);
+    ASSERT_EQ(3u, v[3]);
+    ASSERT_EQ(4u, v[4]);
+    ASSERT_EQ(5u, v[5]);
+  }
+
+  {
+    s.Sort(v, 1);
+    ASSERT_EQ(6u, v.size());
+    ASSERT_EQ(1u, v[0]);
+    ASSERT_EQ(2u, v[1]);
+    ASSERT_EQ(0u, v[2]);
+    ASSERT_EQ(3u, v[3]);
+    ASSERT_EQ(4u, v[4]);
+    ASSERT_EQ(5u, v[5]);
+  }
+
+  {
+    s.Sort(v, 2);
+    ASSERT_EQ(6u, v.size());
+    ASSERT_EQ(2u, v[0]);
+    ASSERT_EQ(3u, v[1]);
+    ASSERT_EQ(1u, v[2]);
+    ASSERT_EQ(4u, v[3]);
+    ASSERT_EQ(0u, v[4]);
+    ASSERT_EQ(5u, v[5]);
+  }
+
+  {
+    s.Sort(v, 3);
+    ASSERT_EQ(6u, v.size());
+    ASSERT_EQ(3u, v[0]);
+    ASSERT_EQ(4u, v[1]);
+    ASSERT_EQ(2u, v[2]);
+    ASSERT_EQ(5u, v[3]);
+    ASSERT_EQ(1u, v[4]);
+    ASSERT_EQ(0u, v[5]);
+  }
+
+  {
+    s.Sort(v, 4);
+    ASSERT_EQ(6u, v.size());
+    ASSERT_EQ(4u, v[0]);
+    ASSERT_EQ(5u, v[1]);
+    ASSERT_EQ(3u, v[2]);
+    ASSERT_EQ(2u, v[3]);
+    ASSERT_EQ(1u, v[4]);
+    ASSERT_EQ(0u, v[5]);
+  }
+
+  {
+    s.Sort(v, 5);
+    ASSERT_EQ(6u, v.size());
+    ASSERT_EQ(5u, v[0]);
+    ASSERT_EQ(4u, v[1]);
+    ASSERT_EQ(3u, v[2]);
+    ASSERT_EQ(2u, v[3]);
+    ASSERT_EQ(1u, v[4]);
+    ASSERT_EQ(0u, v[5]);
+  }
+}
--- a/UnitTestsSources/UnitTestsMain.cpp	Thu May 16 19:10:38 2019 +0200
+++ b/UnitTestsSources/UnitTestsMain.cpp	Tue May 21 13:25:58 2019 +0200
@@ -730,6 +730,82 @@
   ASSERT_TRUE(OrthancStone::MessagingToolbox::ParseJson(response, source.c_str(), source.size()));
 }
 
+TEST(VolumeImageGeometry, Basic)
+{
+  OrthancStone::VolumeImageGeometry g;
+  g.SetSize(10, 20, 30);
+  g.SetVoxelDimensions(1, 2, 3);
+
+  OrthancStone::Vector p = g.GetCoordinates(0, 0, 0);
+  ASSERT_EQ(3u, p.size());
+  ASSERT_FLOAT_EQ(-1.0 / 2.0, p[0]);
+  ASSERT_FLOAT_EQ(-2.0 / 2.0, p[1]);
+  ASSERT_FLOAT_EQ(-3.0 / 2.0, p[2]);
+  
+  p = g.GetCoordinates(1, 1, 1);
+  ASSERT_FLOAT_EQ(-1.0 / 2.0 + 10.0 * 1.0, p[0]);
+  ASSERT_FLOAT_EQ(-2.0 / 2.0 + 20.0 * 2.0, p[1]);
+  ASSERT_FLOAT_EQ(-3.0 / 2.0 + 30.0 * 3.0, p[2]);
+
+  OrthancStone::VolumeProjection proj;
+  ASSERT_TRUE(g.DetectProjection(proj, g.GetAxialGeometry().GetNormal()));
+  ASSERT_EQ(OrthancStone::VolumeProjection_Axial, proj);
+  ASSERT_TRUE(g.DetectProjection(proj, g.GetCoronalGeometry().GetNormal()));
+  ASSERT_EQ(OrthancStone::VolumeProjection_Coronal, proj);
+  ASSERT_TRUE(g.DetectProjection(proj, g.GetSagittalGeometry().GetNormal()));
+  ASSERT_EQ(OrthancStone::VolumeProjection_Sagittal, proj);
+
+  ASSERT_EQ(10u, g.GetProjectionWidth(OrthancStone::VolumeProjection_Axial));
+  ASSERT_EQ(20u, g.GetProjectionHeight(OrthancStone::VolumeProjection_Axial));
+  ASSERT_EQ(30u, g.GetProjectionDepth(OrthancStone::VolumeProjection_Axial));
+  ASSERT_EQ(10u, g.GetProjectionWidth(OrthancStone::VolumeProjection_Coronal));
+  ASSERT_EQ(30u, g.GetProjectionHeight(OrthancStone::VolumeProjection_Coronal));
+  ASSERT_EQ(20u, g.GetProjectionDepth(OrthancStone::VolumeProjection_Coronal));
+  ASSERT_EQ(20u, g.GetProjectionWidth(OrthancStone::VolumeProjection_Sagittal));
+  ASSERT_EQ(30u, g.GetProjectionHeight(OrthancStone::VolumeProjection_Sagittal));
+  ASSERT_EQ(10u, g.GetProjectionDepth(OrthancStone::VolumeProjection_Sagittal));
+
+  p = g.GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
+  ASSERT_EQ(3u, p.size());
+  ASSERT_FLOAT_EQ(1, p[0]);
+  ASSERT_FLOAT_EQ(2, p[1]);
+  ASSERT_FLOAT_EQ(3, p[2]);
+  p = g.GetVoxelDimensions(OrthancStone::VolumeProjection_Coronal);
+  ASSERT_EQ(3u, p.size());
+  ASSERT_FLOAT_EQ(1, p[0]);
+  ASSERT_FLOAT_EQ(3, p[1]);
+  ASSERT_FLOAT_EQ(2, p[2]);
+  p = g.GetVoxelDimensions(OrthancStone::VolumeProjection_Sagittal);
+  ASSERT_EQ(3u, p.size());
+  ASSERT_FLOAT_EQ(2, p[0]);
+  ASSERT_FLOAT_EQ(3, p[1]);
+  ASSERT_FLOAT_EQ(1, p[2]);
+
+  ASSERT_EQ(0, (int) OrthancStone::VolumeProjection_Axial);
+  ASSERT_EQ(1, (int) OrthancStone::VolumeProjection_Coronal);
+  ASSERT_EQ(2, (int) OrthancStone::VolumeProjection_Sagittal);
+  
+  for (int p = 0; p < 3; p++)
+  {
+    OrthancStone::VolumeProjection projection = (OrthancStone::VolumeProjection) p;
+    const OrthancStone::CoordinateSystem3D& s = g.GetProjectionGeometry(projection);
+    
+    for (unsigned int i = 0; i < g.GetProjectionDepth(projection); i++)
+    {
+      OrthancStone::CoordinateSystem3D plane(
+        s.GetOrigin() + static_cast<double>(i) * s.GetNormal() * g.GetVoxelDimensions(projection)[2],
+        s.GetAxisX(),
+        s.GetAxisY());
+
+      unsigned int slice;
+      OrthancStone::VolumeProjection q;
+      ASSERT_TRUE(g.DetectSlice(q, slice, plane));
+      ASSERT_EQ(projection, q);
+      ASSERT_EQ(i, slice);
+    }
+  }
+}
+
 int main(int argc, char **argv)
 {
   Orthanc::Logging::Initialize();