changeset 281:300d8b8c48b3 am-2

mouse tracker tuning
author am@osimis.io
date Tue, 28 Aug 2018 10:01:31 +0200
parents 829163c6efc1
children 38b0ac8055b9
files Applications/Samples/SimpleViewerApplication.h Framework/Viewport/IMouseTracker.h Framework/Widgets/IWorldSceneInteractor.h Framework/Widgets/IWorldSceneMouseTracker.h Framework/Widgets/TestWorldSceneWidget.cpp Framework/Widgets/WorldSceneWidget.cpp Framework/Widgets/WorldSceneWidget.h Resources/CMake/OrthancStoneConfiguration.cmake TODO
diffstat 9 files changed, 147 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/SimpleViewerApplication.h	Mon Aug 27 16:22:08 2018 +0200
+++ b/Applications/Samples/SimpleViewerApplication.h	Tue Aug 28 10:01:31 2018 +0200
@@ -24,6 +24,7 @@
 #include "SampleApplicationBase.h"
 
 #include "../../Framework/Layers/OrthancFrameLayerSource.h"
+#include "../../Framework/Layers/LineMeasureTracker.h"
 #include "../../Framework/Widgets/LayerWidget.h"
 #include "../../Framework/Widgets/LayoutWidget.h"
 #include "../../Framework/Messages/IObserver.h"
@@ -53,6 +54,7 @@
         virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                             const ViewportGeometry& view,
                                                             MouseButton button,
+                                                            KeyboardModifiers modifiers,
                                                             double x,
                                                             double y,
                                                             IStatusBar* statusBar)
@@ -83,17 +85,17 @@
                                 char key,
                                 KeyboardModifiers modifiers,
                                 IStatusBar* statusBar)
-        {};
+        {}
 
       };
 
-      class Interactor : public IWorldSceneInteractor
+      class MainWidgetInteractor : public IWorldSceneInteractor
       {
       private:
         SimpleViewerApplication&  application_;
         
       public:
-        Interactor(SimpleViewerApplication&  application) :
+        MainWidgetInteractor(SimpleViewerApplication&  application) :
           application_(application)
         {
         }
@@ -101,10 +103,15 @@
         virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                             const ViewportGeometry& view,
                                                             MouseButton button,
+                                                            KeyboardModifiers modifiers,
                                                             double x,
                                                             double y,
                                                             IStatusBar* statusBar)
         {
+          if (button == MouseButton_Left)
+          {
+            return new LineMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(), x, y, 255, 0, 0, 10);
+          }
           return NULL;
         }
 
@@ -166,7 +173,7 @@
       };
 
 
-      std::unique_ptr<Interactor>     interactor_;
+      std::unique_ptr<MainWidgetInteractor> mainWidgetInteractor_;
       std::unique_ptr<ThumbnailInteractor>  thumbnailInteractor_;
       LayoutWidget*                   mainLayout_;
       LayoutWidget*                   thumbnailsLayout_;
@@ -248,8 +255,8 @@
           smartLoader_->SetImageQuality(SliceImageQuality_FullPam);
 
           mainLayout_->SetTransmitMouseOver(true);
-          interactor_.reset(new Interactor(*this));
-          mainWidget_->SetInteractor(*interactor_);
+          mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
+          mainWidget_->SetInteractor(*mainWidgetInteractor_);
           thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
         }
 
--- a/Framework/Viewport/IMouseTracker.h	Mon Aug 27 16:22:08 2018 +0200
+++ b/Framework/Viewport/IMouseTracker.h	Tue Aug 28 10:01:31 2018 +0200
@@ -25,6 +25,9 @@
 
 namespace OrthancStone
 {
+  // this is tracking a mouse in screen coordinates/pixels unlike
+  // the IWorldSceneMouseTracker that is tracking a mouse
+  // in scene coordinates/mm.
   class IMouseTracker : public boost::noncopyable
   {
   public:
--- a/Framework/Widgets/IWorldSceneInteractor.h	Mon Aug 27 16:22:08 2018 +0200
+++ b/Framework/Widgets/IWorldSceneInteractor.h	Tue Aug 28 10:01:31 2018 +0200
@@ -41,6 +41,7 @@
     virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                         const ViewportGeometry& view,
                                                         MouseButton button,
+                                                        KeyboardModifiers modifiers,
                                                         double x,
                                                         double y,
                                                         IStatusBar* statusBar) = 0;
--- a/Framework/Widgets/IWorldSceneMouseTracker.h	Mon Aug 27 16:22:08 2018 +0200
+++ b/Framework/Widgets/IWorldSceneMouseTracker.h	Tue Aug 28 10:01:31 2018 +0200
@@ -13,7 +13,7 @@
  * 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/>.
  **/
@@ -25,16 +25,20 @@
 
 namespace OrthancStone
 {
+
+  // this is tracking a mouse in scene coordinates/mm unlike
+  // the IMouseTracker that is tracking a mouse
+  // in screen coordinates/pixels.
   class IWorldSceneMouseTracker : public boost::noncopyable
   {
   public:
     virtual ~IWorldSceneMouseTracker()
     {
     }
-    
+
     virtual void Render(CairoContext& context,
                         double zoom) = 0;
-    
+
     virtual void MouseUp() = 0;
 
     virtual void MouseMove(double x,
--- a/Framework/Widgets/TestWorldSceneWidget.cpp	Mon Aug 27 16:22:08 2018 +0200
+++ b/Framework/Widgets/TestWorldSceneWidget.cpp	Tue Aug 28 10:01:31 2018 +0200
@@ -34,6 +34,7 @@
       virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                           const ViewportGeometry& view,
                                                           MouseButton button,
+                                                          KeyboardModifiers modifiers,
                                                           double x,
                                                           double y,
                                                           IStatusBar* statusBar)
--- a/Framework/Widgets/WorldSceneWidget.cpp	Mon Aug 27 16:22:08 2018 +0200
+++ b/Framework/Widgets/WorldSceneWidget.cpp	Tue Aug 28 10:01:31 2018 +0200
@@ -13,7 +13,7 @@
  * 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/>.
  **/
@@ -59,12 +59,16 @@
   };
 
 
+  // this is an adapter between a IWorldSceneMouseTracker
+  // that is tracking a mouse in scene coordinates/mm and
+  // an IMouseTracker that is tracking a mouse
+  // in screen coordinates/pixels.
   class WorldSceneWidget::SceneMouseTracker : public IMouseTracker
   {
   private:
     ViewportGeometry                       view_;
     std::auto_ptr<IWorldSceneMouseTracker>  tracker_;
-      
+
   public:
     SceneMouseTracker(const ViewportGeometry& view,
                       IWorldSceneMouseTracker* tracker) :
@@ -77,17 +81,17 @@
     virtual void Render(Orthanc::ImageAccessor& target)
     {
       CairoSurface surface(target);
-      CairoContext context(surface); 
+      CairoContext context(surface);
       view_.ApplyTransform(context);
       tracker_->Render(context, view_.GetZoom());
     }
 
-    virtual void MouseUp() 
+    virtual void MouseUp()
     {
       tracker_->MouseUp();
     }
 
-    virtual void MouseMove(int x, 
+    virtual void MouseMove(int x,
                            int y)
     {
       double sceneX, sceneY;
@@ -97,121 +101,80 @@
   };
 
 
-  class WorldSceneWidget::PanMouseTracker : public IMouseTracker
+  WorldSceneWidget::PanMouseTracker::PanMouseTracker(WorldSceneWidget& that,
+                                                     int x,
+                                                     int y) :
+    that_(that),
+    downX_(x),
+    downY_(y)
   {
-  private:
-    WorldSceneWidget&  that_;  
-    double             previousPanX_;
-    double             previousPanY_;
-    double             downX_;
-    double             downY_;
+    that_.view_.GetPan(previousPanX_, previousPanY_);
+  }
+
+  void WorldSceneWidget::PanMouseTracker::MouseMove(int x, int y)
+  {
+    that_.view_.SetPan(previousPanX_ + x - downX_,
+                       previousPanY_ + y - downY_);
+
+    that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_);
+  }
 
-  public:
-    PanMouseTracker(WorldSceneWidget& that,
-                    int x,
-                    int y) :
-      that_(that),
-      downX_(x),
-      downY_(y)
+  WorldSceneWidget::ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget&  that,
+                                                       int x,
+                                                       int y) :
+    that_(that),
+    downX_(x),
+    downY_(y)
+  {
+    oldZoom_ = that_.view_.GetZoom();
+    MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_);
+  }
+
+  void WorldSceneWidget::ZoomMouseTracker::MouseMove(int x,
+                                                     int y)
+  {
+    static const double MIN_ZOOM = -4;
+    static const double MAX_ZOOM = 4;
+
+    if (that_.view_.GetDisplayHeight() <= 3)
     {
-      that_.view_.GetPan(previousPanX_, previousPanY_);
-    }
-
-    virtual void Render(Orthanc::ImageAccessor& surface)
-    {
-    }
-
-    virtual void MouseUp() 
-    {
+      return;   // Cannot zoom on such a small image
     }
 
-    virtual void MouseMove(int x, 
-                           int y)
-    {
-      that_.view_.SetPan(previousPanX_ + x - downX_,
-                         previousPanY_ + y - downY_);
-
-      that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_);
-    }
-  };
-
+    double dy = (static_cast<double>(y - downY_) /
+                 static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1]
+    double z;
 
-  class WorldSceneWidget::ZoomMouseTracker : public IMouseTracker
-  {
-  private:
-    WorldSceneWidget&  that_;  
-    int                downX_;
-    int                downY_;
-    double             centerX_;
-    double             centerY_;
-    double             oldZoom_;
-
-  public:
-    ZoomMouseTracker(WorldSceneWidget&  that,
-                     int x,
-                     int y) :
-      that_(that),
-      downX_(x),
-      downY_(y)
+    // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
+    if (dy < -1.0)
     {
-      oldZoom_ = that_.view_.GetZoom();
-      MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_);
+      z = MIN_ZOOM;
     }
-
-    virtual void Render(Orthanc::ImageAccessor& surface)
+    else if (dy > 1.0)
     {
+      z = MAX_ZOOM;
     }
-
-    virtual void MouseUp() 
+    else
     {
+      z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0;
     }
 
-    virtual void MouseMove(int x, 
-                           int y)
-    {
-      static const double MIN_ZOOM = -4;
-      static const double MAX_ZOOM = 4;
+    z = pow(2.0, z);
 
-      if (that_.view_.GetDisplayHeight() <= 3)
-      {
-        return;   // Cannot zoom on such a small image
-      }
-
-      double dy = (static_cast<double>(y - downY_) / 
-                   static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1]
-      double z;
+    that_.view_.SetZoom(oldZoom_ * z);
 
-      // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
-      if (dy < -1.0)
-      {
-        z = MIN_ZOOM;
-      }
-      else if (dy > 1.0)
-      {
-        z = MAX_ZOOM;
-      }
-      else
-      {
-        z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0;
-      }
-
-      z = pow(2.0, z);
+    // Correct the pan so that the original click point is kept at
+    // the same location on the display
+    double panX, panY;
+    that_.view_.GetPan(panX, panY);
 
-      that_.view_.SetZoom(oldZoom_ * z);
-
-      // Correct the pan so that the original click point is kept at
-      // the same location on the display
-      double panX, panY;
-      that_.view_.GetPan(panX, panY);
+    int tx, ty;
+    that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_);
+    that_.view_.SetPan(panX + static_cast<double>(downX_ - tx),
+                       panY + static_cast<double>(downY_ - ty));
 
-      int tx, ty;
-      that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_);
-      that_.view_.SetPan(panX + static_cast<double>(downX_ - tx),
-                               panY + static_cast<double>(downY_ - ty));
-
-      that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_);
-    }
-  };
+    that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_);
+  }
 
 
   bool WorldSceneWidget::RenderCairo(CairoContext& context)
@@ -302,24 +265,25 @@
     double sceneX, sceneY;
     MapMouseToScene(sceneX, sceneY, view_, x, y);
 
+    // asks the Widget Interactor to provide a mouse tracker
     std::auto_ptr<IWorldSceneMouseTracker> tracker
-      (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers));
+        (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers));
 
     if (tracker.get() != NULL)
     {
       return new SceneMouseTracker(view_, tracker.release());
     }
-
+    //TODO: allow Interactor to create Pan & Zoom
     switch (button)
     {
-      case MouseButton_Middle:
-        return new PanMouseTracker(*this, x, y);
+    case MouseButton_Middle:
+      return new PanMouseTracker(*this, x, y);
 
-      case MouseButton_Right:
-        return new ZoomMouseTracker(*this, x, y);
+    case MouseButton_Right:
+      return new ZoomMouseTracker(*this, x, y);
 
-      default:
-        return NULL;
+    default:
+      return NULL;
     }
   }
 
@@ -343,7 +307,7 @@
   {
     if (interactor_)
     {
-      return interactor_->CreateMouseTracker(*this, view, button, x, y, GetStatusBar());
+      return interactor_->CreateMouseTracker(*this, view, button, modifiers, x, y, GetStatusBar());
     }
     else
     {
@@ -355,7 +319,7 @@
   void WorldSceneWidget::MouseWheel(MouseWheelDirection direction,
                                     int x,
                                     int y,
-                                    KeyboardModifiers modifiers) 
+                                    KeyboardModifiers modifiers)
   {
     if (interactor_)
     {
--- a/Framework/Widgets/WorldSceneWidget.h	Mon Aug 27 16:22:08 2018 +0200
+++ b/Framework/Widgets/WorldSceneWidget.h	Tue Aug 28 10:01:31 2018 +0200
@@ -13,7 +13,7 @@
  * 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/>.
  **/
@@ -46,12 +46,49 @@
                                     const ViewportGeometry& view) = 0;
     };
 
+    class PanMouseTracker : public IMouseTracker
+    {
+    private:
+      WorldSceneWidget&  that_;
+      double             previousPanX_;
+      double             previousPanY_;
+      double             downX_;
+      double             downY_;
+
+    public:
+      PanMouseTracker(WorldSceneWidget& that, int x, int y);
+
+      virtual void Render(Orthanc::ImageAccessor& surface) {}
+
+      virtual void MouseUp() {}
+
+      virtual void MouseMove(int x, int y);
+    };
+
+    class ZoomMouseTracker : public IMouseTracker
+    {
+    private:
+      WorldSceneWidget&  that_;
+      int                downX_;
+      int                downY_;
+      double             centerX_;
+      double             centerY_;
+      double             oldZoom_;
+
+    public:
+      ZoomMouseTracker(WorldSceneWidget&  that, int x, int y);
+
+      void Render(Orthanc::ImageAccessor& surface) {}
+
+      virtual void MouseUp() {}
+
+      virtual void MouseMove(int x, int y);
+    };
+
   private:
     struct SizeChangeFunctor;
 
     class SceneMouseTracker;
-    class PanMouseTracker;
-    class ZoomMouseTracker;
 
     typedef ObserversRegistry<WorldSceneWidget, IWorldObserver>  Observers;
 
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Mon Aug 27 16:22:08 2018 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Aug 28 10:01:31 2018 +0200
@@ -253,6 +253,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeReslicer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/CairoWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/EmptyWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneMouseTracker.h
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/LayerWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/LayoutWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/TestCairoWidget.cpp
--- a/TODO	Mon Aug 27 16:22:08 2018 +0200
+++ b/TODO	Tue Aug 28 10:01:31 2018 +0200
@@ -9,7 +9,9 @@
 * Documentation
 * Interface with DICOMweb
 * LayoutPetCtFusionApplication: fix initial view
-
+* Allow Interactor to create Pan/ZoomMouseTracker in IWorldSceneMouseTracker* CreateMouseTracker 
+  (problem: PanMouseTracker is a IMouseTracker and CreateMouseTracker shall return a IWorldSceneMouseTracker).
+  WorldSceneWidet shall not create Pan/ZoomMouseTracker when the Interactor does not create one
 
 ---------------------------------
 Radiotherapy and nuclear medicine
@@ -25,8 +27,8 @@
 Optimizations
 -------------
 
+* Add cache in "SmartLoader" by returning a "OrthancFrameLayerSource" for a frame that has already been loaded
 * Tune number of loading threads in LayeredSceneWidget
-* Add cache over IOrthancServices (for SDL/Qt/...)
 * LayoutWidget: Do not update full background if only 1 widget has changed
 * LayoutWidget: Threads to refresh each child
 * Implement binary search to speed up search for closest slice
@@ -38,7 +40,6 @@
 Platform-specific
 -----------------
 
-* Qt widget example
 * Add precompiled headers for Microsoft Visual Studio
 * Investigate crash in CurlOrthancConnection if using MinGW32 in Release mode