changeset 85:bd48431ac285 wasm

fix
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 26 May 2017 12:20:26 +0200
parents c75377306598
children 02c3a7a4938f
files Applications/Samples/SingleFrameApplication.h Framework/Layers/FrameRenderer.cpp Framework/Layers/FrameRenderer.h Framework/Layers/OrthancFrameLayerSource.cpp Framework/Toolbox/Slice.h Framework/Widgets/LayerWidget.cpp Framework/Widgets/LayerWidget.h Framework/Widgets/WidgetBase.cpp Framework/Widgets/WidgetBase.h Framework/Widgets/WorldSceneWidget.cpp
diffstat 10 files changed, 181 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/SingleFrameApplication.h	Wed May 24 23:25:36 2017 +0200
+++ b/Applications/Samples/SingleFrameApplication.h	Fri May 26 12:20:26 2017 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "SampleApplicationBase.h"
+#include "SampleInteractor.h"
 
 #include "../../Framework/Layers/OrthancFrameLayerSource.h"
 #include "../../Framework/Widgets/LayerWidget.h"
@@ -36,6 +37,61 @@
       public IVolumeSlicesObserver
     {
     private:
+      class Interactor : public IWorldSceneInteractor
+      {
+      public:
+        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                            const ViewportGeometry& view,
+                                                            MouseButton button,
+                                                            double x,
+                                                            double y,
+                                                            IStatusBar* statusBar)
+        {
+          return NULL;
+        }
+
+        virtual void MouseOver(CairoContext& context,
+                               WorldSceneWidget& widget,
+                               const ViewportGeometry& view,
+                               double x,
+                               double y,
+                               IStatusBar* statusBar)
+        {
+          if (statusBar != NULL)
+          {
+            Vector p = dynamic_cast<LayerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+            
+            char buf[64];
+            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", 
+                    p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+            statusBar->SetMessage(buf);
+          }
+        }
+
+        virtual void MouseWheel(WorldSceneWidget& widget,
+                                MouseWheelDirection direction,
+                                KeyboardModifiers modifiers,
+                                IStatusBar* statusBar)
+        {
+        }
+
+        virtual void KeyPressed(WorldSceneWidget& widget,
+                                char key,
+                                KeyboardModifiers modifiers,
+                                IStatusBar* statusBar)
+        {
+          switch (key)
+          {
+            case 's':
+              widget.SetDefaultView();
+              break;
+
+            default:
+              break;
+          }
+        }
+      };
+
       LayerWidget* widget_;
       
     public:
@@ -49,6 +105,7 @@
             slices.GetSliceCount() > 0)
         {
           widget_->SetSlice(slices.GetSlice(0));
+          widget_->SetDefaultView();
         }
       }
       
@@ -73,6 +130,8 @@
       {
         using namespace OrthancStone;
 
+        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+
         if (parameters.count("instance") != 1)
         {
           LOG(ERROR) << "The instance ID is missing";
@@ -84,7 +143,7 @@
 
         std::auto_ptr<LayerWidget> widget(new LayerWidget);
 
-#if 0
+#if 1
         std::auto_ptr<OrthancFrameLayerSource> layer
           (new OrthancFrameLayerSource(context.GetWebService(), instance, frame));
         layer->SetObserver(*this);
@@ -106,17 +165,26 @@
 
         widget->AddLayer(new OrthancFrameLayerSource(context.GetWebService(), "a1c4dc6b-255d27f0-88069875-8daed730-2f5ee5c6", 0));
 
-        RenderStyle s;
-        //s.drawGrid_ = true;
-        s.alpha_ = 1;
-        widget->SetLayerStyle(0, s);
-        s.alpha_ = 0.5;
-        s.applyLut_ = true;
-        s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
-        widget->SetLayerStyle(1, s);
+        {
+          RenderStyle s;
+          s.alpha_ = 1;
+          widget->SetLayerStyle(0, s);
+        }
+
+        {
+          RenderStyle s;
+          s.drawGrid_ = true;
+          s.SetColor(255, 0, 0);  // Draw missing PET layer in red
+          s.alpha_ = 0.5;
+          s.applyLut_ = true;
+          s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
+          widget->SetLayerStyle(1, s);
+        }
 #endif
-      
+
         widget_ = widget.get();
+        widget_->SetTransmitMouseOver(true);
+        widget_->SetInteractor(context.AddInteractor(new Interactor));
         context.SetCentralWidget(widget.release());
       }
     };
--- a/Framework/Layers/FrameRenderer.cpp	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Layers/FrameRenderer.cpp	Fri May 26 12:20:26 2017 +0200
@@ -111,7 +111,7 @@
       {
         return true;
       }
-      
+
       x1 = 0;
       y1 = 0;
       cairo_matrix_transform_point(&transform, &x1, &y1);
@@ -239,20 +239,20 @@
 
 
   ILayerRenderer* FrameRenderer::CreateRenderer(Orthanc::ImageAccessor* frame,
-                                                const Slice& slice,
+                                                const Slice& frameSlice,
                                                 bool isFullQuality)
   {
     std::auto_ptr<Orthanc::ImageAccessor> protect(frame);
 
     if (frame->GetFormat() == Orthanc::PixelFormat_RGB24)
     {
-      return new ColorFrameRenderer(protect.release(), slice.GetGeometry(), 
-                                    slice.GetPixelSpacingX(), slice.GetPixelSpacingY(), isFullQuality);
+      return new ColorFrameRenderer(protect.release(), frameSlice.GetGeometry(), 
+                                    frameSlice.GetPixelSpacingX(), frameSlice.GetPixelSpacingY(), isFullQuality);
     }
     else
     {
-      return new GrayscaleFrameRenderer(protect.release(), slice.GetConverter(), slice.GetGeometry(), 
-                                        slice.GetPixelSpacingX(), slice.GetPixelSpacingY(), isFullQuality);
+      return new GrayscaleFrameRenderer(protect.release(), frameSlice.GetConverter(), frameSlice.GetGeometry(), 
+                                        frameSlice.GetPixelSpacingX(), frameSlice.GetPixelSpacingY(), isFullQuality);
     }
   }
 }
--- a/Framework/Layers/FrameRenderer.h	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Layers/FrameRenderer.h	Fri May 26 12:20:26 2017 +0200
@@ -65,11 +65,11 @@
                                    double& x2,
                                    double& y2,
                                    const SliceGeometry& viewportSlice,
-                                   const Slice& slice)
+                                   const Slice& frame)
     {
       return ComputeFrameExtent(x1, y1, x2, y2, viewportSlice,
-                                slice.GetGeometry(), slice.GetWidth(), slice.GetHeight(),
-                                slice.GetPixelSpacingX(), slice.GetPixelSpacingY());
+                                frame.GetGeometry(), frame.GetWidth(), frame.GetHeight(),
+                                frame.GetPixelSpacingX(), frame.GetPixelSpacingY());
     }
 
     virtual bool RenderLayer(CairoContext& context,
@@ -92,7 +92,7 @@
                                           bool isFullQuality);
 
     static ILayerRenderer* CreateRenderer(Orthanc::ImageAccessor* frame,
-                                          const Slice& slice,
+                                          const Slice& frameSlice,
                                           bool isFullQuality);
   };
 }
--- a/Framework/Layers/OrthancFrameLayerSource.cpp	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Layers/OrthancFrameLayerSource.cpp	Fri May 26 12:20:26 2017 +0200
@@ -48,6 +48,8 @@
       }
     }
 
+    LayerSourceBase::NotifyGeometryReady();
+
     if (observer2_ != NULL)
     {
       ParallelSlices slices;
@@ -59,8 +61,6 @@
 
       observer2_->NotifySlicesAvailable(slices);
     }
-      
-    LayerSourceBase::NotifyGeometryReady();
   }
 
   void OrthancFrameLayerSource::NotifyGeometryError(const OrthancSlicesLoader& loader)
@@ -123,12 +123,11 @@
                                           double& y1,
                                           double& x2,
                                           double& y2,
-                                          const SliceGeometry& viewportSlice /* ignored */)
+                                          const SliceGeometry& viewportSlice)
   {
     bool ok = false;
 
-    if (IsStarted() &&
-        loader_.IsGeometryReady())
+    if (loader_.IsGeometryReady())
     {
       double tx1, ty1, tx2, ty2;
 
@@ -164,12 +163,8 @@
   {
     size_t index;
 
-    if (!IsStarted() ||
-        !loader_.IsGeometryReady())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else if (loader_.LookupSlice(index, viewportSlice))
+    if (loader_.IsGeometryReady() &&
+        loader_.LookupSlice(index, viewportSlice))
     {
       loader_.ScheduleLoadSliceImage(index);
     }
--- a/Framework/Toolbox/Slice.h	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Toolbox/Slice.h	Fri May 26 12:20:26 2017 +0200
@@ -32,6 +32,7 @@
     enum Type
     {
       Type_Invalid,
+      Type_Detached,
       Type_OrthancInstance
       // TODO A slice could come from some DICOM file (URL)
     };
@@ -52,6 +53,21 @@
     {        
     }
 
+    // TODO Is this constructor the best way to go to tackle missing
+    // layers within LayerWidget?
+    Slice(const SliceGeometry& plane,
+          double thickness) :
+      type_(Type_Detached),
+      frame_(0),
+      geometry_(plane),
+      pixelSpacingX_(1),
+      pixelSpacingY_(1),
+      thickness_(thickness),
+      width_(0),
+      height_(0)
+    {      
+    }
+
     bool ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset,
                            const std::string& instanceId,
                            unsigned int frame);
--- a/Framework/Widgets/LayerWidget.cpp	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Widgets/LayerWidget.cpp	Fri May 26 12:20:26 2017 +0200
@@ -22,6 +22,9 @@
 #include "LayerWidget.h"
 
 #include "../../Resources/Orthanc/Core/Logging.h"
+#include "../Layers/MissingLayerRenderer.h"
+
+static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits<double>::epsilon();
 
 namespace OrthancStone
 {
@@ -158,6 +161,33 @@
     }
   }
     
+
+  bool LayerWidget::GetAndFixExtent(double& x1,
+                                    double& y1,
+                                    double& x2,
+                                    double& y2,
+                                    ILayerSource& source) const
+  {
+    if (source.GetExtent(x1, y1, x2, y2, slice_))
+    {
+      if (x1 > x2)
+      {
+        std::swap(x1, x2);
+      }
+
+      if (y1 > y2)
+      {
+        std::swap(y1, y2);
+      }
+
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
         
   void LayerWidget::GetSceneExtent(double& x1,
                                    double& y1,
@@ -171,18 +201,8 @@
       double ax, ay, bx, by;
 
       assert(layers_[i] != NULL);
-      if (layers_[i]->GetExtent(ax, ay, bx, by, slice_))
+      if (GetAndFixExtent(ax, ay, bx, by, *layers_[i]))
       {
-        if (ax > bx)
-        {
-          std::swap(ax, bx);
-        }
-
-        if (ay > by)
-        {
-          std::swap(ay, by);
-        }
-
         LOG(INFO) << "Extent of layer " << i << ": (" << ax << "," << ay << ")->(" << bx << "," << by << ")";
 
         if (first)
@@ -353,7 +373,7 @@
 
   void LayerWidget::SetSlice(const SliceGeometry& slice)
   {
-    if (!slice_.IsSamePlane(slice, 100.0 * std::numeric_limits<double>::epsilon()))
+    if (!slice_.IsSamePlane(slice, THIN_SLICE_THICKNESS))
     {
       if (currentScene_.get() == NULL ||
           (pendingScene_.get() != NULL &&
@@ -365,13 +385,10 @@
       slice_ = slice;
       ResetPendingScene();
 
-      if (started_)
+      for (size_t i = 0; i < layers_.size(); i++)
       {
-        for (size_t i = 0; i < layers_.size(); i++)
-        {
-          assert(layers_[i] != NULL);
-          layers_[i]->ScheduleLayerCreation(slice_);
-        }
+        assert(layers_[i] != NULL);
+        layers_[i]->ScheduleLayerCreation(slice_);
       }
     }
   }
@@ -383,7 +400,6 @@
     if (LookupLayer(i, source))
     {
       LOG(INFO) << "Geometry ready for layer " << i;
-      SetDefaultView();
       layers_[i]->ScheduleLayerCreation(slice_);
     }
   }
@@ -418,7 +434,8 @@
     std::auto_ptr<ILayerRenderer> tmp(renderer);
 
     size_t index;
-    if (LookupLayer(index, source))
+    if (LookupLayer(index, source) &&
+        slice.ContainsPlane(slice_))  // Whether the slice comes from an older request
     {
       LOG(INFO) << "Renderer ready for layer " << index;
       UpdateLayer(index, tmp.release(), slice);
@@ -427,11 +444,21 @@
 
   
   void LayerWidget::NotifyLayerError(ILayerSource& source,
-                                     const SliceGeometry& viewportSlice)
+                                     const SliceGeometry& slice)
   {
-    size_t i;
-    if (LookupLayer(i, source))
-      LOG(ERROR) << "Error on layer " << i;
+    size_t index;
+
+    if (LookupLayer(index, source) &&
+        slice.IsSamePlane(slice_, THIN_SLICE_THICKNESS))  // Whether the slice comes from an older request
+    {
+      LOG(ERROR) << "Error on layer " << index;
+
+      double x1, y1, x2, y2;
+      if (GetAndFixExtent(x1, y1, x2, y2, source))
+      {
+        UpdateLayer(index, new MissingLayerRenderer(x1, y1, x2, y2), Slice(slice, THIN_SLICE_THICKNESS));
+      }
+    }
   }    
 
 
--- a/Framework/Widgets/LayerWidget.h	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Widgets/LayerWidget.h	Fri May 26 12:20:26 2017 +0200
@@ -48,7 +48,12 @@
 
     bool LookupLayer(size_t& index /* out */,
                      ILayerSource& layer) const;
-    
+
+    bool GetAndFixExtent(double& x1,
+                         double& y1,
+                         double& x2,
+                         double& y2,
+                         ILayerSource& source) const;
 
     virtual void NotifyGeometryReady(ILayerSource& source);
 
@@ -94,6 +99,11 @@
 
     void SetSlice(const SliceGeometry& slice);
 
+    const SliceGeometry& GetSlice() const
+    {
+      return slice_;
+    }
+
     virtual void Start();
   };
 }
--- a/Framework/Widgets/WidgetBase.cpp	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Widgets/WidgetBase.cpp	Fri May 26 12:20:26 2017 +0200
@@ -105,7 +105,8 @@
     parent_(NULL),
     viewport_(NULL),
     statusBar_(NULL),
-    backgroundCleared_(false)
+    backgroundCleared_(false),
+    transmitMouseOver_(false)
   {
     backgroundColor_[0] = 0;
     backgroundColor_[1] = 0;
--- a/Framework/Widgets/WidgetBase.h	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Widgets/WidgetBase.h	Fri May 26 12:20:26 2017 +0200
@@ -35,6 +35,7 @@
     IStatusBar*  statusBar_;
     bool         backgroundCleared_;
     uint8_t      backgroundColor_[3];
+    bool         transmitMouseOver_;
 
   protected:
     void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const;
@@ -71,6 +72,11 @@
       return backgroundCleared_;
     }
 
+    void SetTransmitMouseOver(bool transmit)
+    {
+      transmitMouseOver_ = transmit;
+    }
+
     void SetBackgroundColor(uint8_t red,
                             uint8_t green,
                             uint8_t blue);
@@ -95,7 +101,7 @@
 
     virtual bool HasRenderMouseOver()
     {
-      return false;
+      return transmitMouseOver_;
     }
 
     virtual void NotifyChange();
--- a/Framework/Widgets/WorldSceneWidget.cpp	Wed May 24 23:25:36 2017 +0200
+++ b/Framework/Widgets/WorldSceneWidget.cpp	Fri May 26 12:20:26 2017 +0200
@@ -21,8 +21,6 @@
 
 #include "WorldSceneWidget.h"
 
-#include "../../Resources/Orthanc/Core/OrthancException.h"
-
 namespace OrthancStone
 {
   static void MapMouseToScene(double& sceneX,