changeset 1554:6d14ed6163b1

flip x/y in Stone Web viewer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 17 Aug 2020 16:10:00 +0200
parents bf02a90ca9ca
children b894072b9e2f
files Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Scene2D/TextureBaseSceneLayer.cpp OrthancStone/Sources/Scene2D/TextureBaseSceneLayer.h OrthancStone/Sources/Toolbox/AffineTransform2D.cpp OrthancStone/Sources/Toolbox/AffineTransform2D.h
diffstat 7 files changed, 185 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebApplication/app.js	Mon Aug 17 13:25:54 2020 +0200
+++ b/Applications/StoneWebViewer/WebApplication/app.js	Mon Aug 17 16:10:00 2020 +0200
@@ -466,6 +466,20 @@
       }
     },
 
+    FlipX() {
+      var canvas = this.GetActiveCanvas();
+      if (canvas != '') {
+        stone.FlipX(canvas);
+      }
+    },
+
+    FlipY() {
+      var canvas = this.GetActiveCanvas();
+      if (canvas != '') {
+        stone.FlipY(canvas);
+      }
+    },
+
     ApplyPreferences() {
       this.modalPreferences = false;
 
--- a/Applications/StoneWebViewer/WebApplication/index.html	Mon Aug 17 13:25:54 2020 +0200
+++ b/Applications/StoneWebViewer/WebApplication/index.html	Mon Aug 17 16:10:00 2020 +0200
@@ -315,6 +315,18 @@
             </div>
 
             <div class="ng-scope inline-object">
+              <button class="wvButton--underline text-center" v-on:click="FlipX()">
+                <i class="fas fa-exchange-alt"></i>X
+              </button>
+            </div>
+
+            <div class="ng-scope inline-object">
+              <button class="wvButton--underline text-center" v-on:click="FlipY()">
+                <i class="fa fa-exchange-alt fa-rotate-90"></i>Y
+              </button>
+            </div>
+            
+            <div class="ng-scope inline-object">
               <button class="wvButton--underline text-center"
                       v-bind:class="{ 'active' : showInfo }"
                       v-on:click="showInfo = !showInfo">
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Mon Aug 17 13:25:54 2020 +0200
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Mon Aug 17 16:10:00 2020 +0200
@@ -1234,6 +1234,8 @@
   float                                        defaultWindowingCenter_;
   float                                        defaultWindowingWidth_;
   bool                                         inverted_;
+  bool                                         flipX_;
+  bool                                         flipY_;
   bool                                         fitNextContent_;
   bool                                         isCtrlDown_;
   FrameGeometry                                currentFrameGeometry_;
@@ -1425,6 +1427,8 @@
       }
 
       layer->SetLinearInterpolation(true);
+      layer->SetFlipX(flipX_);
+      layer->SetFlipY(flipY_);
 
       double pixelSpacingX, pixelSpacingY;
       OrthancStone::GeometryToolbox::GetPixelSpacing(
@@ -1519,6 +1523,34 @@
     }
   }
 
+  void UpdateCurrentTextureParameters()
+  {
+    std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
+
+    if (lock->GetController().GetScene().HasLayer(LAYER_TEXTURE))
+    {
+      if (lock->GetController().GetScene().GetLayer(LAYER_TEXTURE).GetType() ==
+          OrthancStone::ISceneLayer::Type_FloatTexture)
+      {
+        dynamic_cast<OrthancStone::FloatTextureSceneLayer&>(
+          lock->GetController().GetScene().GetLayer(LAYER_TEXTURE)).
+          SetCustomWindowing(windowingCenter_, windowingWidth_);
+      }
+
+      {
+        OrthancStone::TextureBaseSceneLayer& layer = 
+          dynamic_cast<OrthancStone::TextureBaseSceneLayer&>(
+            lock->GetController().GetScene().GetLayer(LAYER_TEXTURE));
+
+        layer.SetFlipX(flipX_);
+        layer.SetFlipY(flipY_);
+      }
+        
+      lock->Invalidate();
+    }
+  }
+  
+
   ViewerViewport(OrthancStone::ILoadersContext& context,
                  const OrthancStone::DicomSource& source,
                  const std::string& canvas,
@@ -1528,7 +1560,9 @@
     source_(source),
     cache_(cache),
     fitNextContent_(true),
-    isCtrlDown_(false)
+    isCtrlDown_(false),
+    flipX_(false),
+    flipY_(false)
   {
     if (!cache_)
     {
@@ -1551,6 +1585,29 @@
     emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey);
 
     ResetDefaultWindowing();
+
+    /*{
+      std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
+      std::unique_ptr<OrthancStone::PolylineSceneLayer> layer(new OrthancStone::PolylineSceneLayer);
+      OrthancStone::PolylineSceneLayer::Chain chain;
+      chain.push_back(OrthancStone::ScenePoint2D(-10, 0));
+      chain.push_back(OrthancStone::ScenePoint2D(10, 0));
+      layer->AddChain(chain, false, 255, 0, 0);
+      chain.clear();
+      chain.push_back(OrthancStone::ScenePoint2D(0, -10));
+      chain.push_back(OrthancStone::ScenePoint2D(0, 10));
+      layer->AddChain(chain, false, 255, 0, 0);
+      chain.clear();
+      chain.push_back(OrthancStone::ScenePoint2D(40, 30));
+      chain.push_back(OrthancStone::ScenePoint2D(40, 50));
+      layer->AddChain(chain, false, 255, 0, 0);
+      chain.clear();
+      chain.push_back(OrthancStone::ScenePoint2D(30, 40));
+      chain.push_back(OrthancStone::ScenePoint2D(50, 40));
+      layer->AddChain(chain, false, 255, 0, 0);
+      lock->GetController().GetScene().SetLayer(1000, layer.release());
+      lock->Invalidate();
+      }*/
   }
 
   static EM_BOOL OnKey(int eventType,
@@ -1634,6 +1691,8 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
     }
 
+    flipX_ = false;
+    flipY_ = false;
     fitNextContent_ = true;
 
     frames_.reset(frames);
@@ -1776,20 +1835,19 @@
   {
     windowingCenter_ = windowingCenter;
     windowingWidth_ = windowingWidth;
-
-    {
-      std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
+    UpdateCurrentTextureParameters();
+  }
 
-      if (lock->GetController().GetScene().HasLayer(LAYER_TEXTURE) &&
-          lock->GetController().GetScene().GetLayer(LAYER_TEXTURE).GetType() ==
-          OrthancStone::ISceneLayer::Type_FloatTexture)
-      {
-        dynamic_cast<OrthancStone::FloatTextureSceneLayer&>(
-          lock->GetController().GetScene().GetLayer(LAYER_TEXTURE)).
-          SetCustomWindowing(windowingCenter_, windowingWidth_);
-        lock->Invalidate();
-      }
-    }
+  void FlipX()
+  {
+    flipX_ = !flipX_;
+    UpdateCurrentTextureParameters();
+  }
+
+  void FlipY()
+  {
+    flipY_ = !flipY_;
+    UpdateCurrentTextureParameters();
   }
 
   void Invert()
@@ -2285,6 +2343,28 @@
 
 
   EMSCRIPTEN_KEEPALIVE
+  void FlipX(const char* canvas)
+  {
+    try
+    {
+      GetViewport(canvas)->FlipX();
+    }
+    EXTERN_CATCH_EXCEPTIONS;
+  }  
+
+
+  EMSCRIPTEN_KEEPALIVE
+  void FlipY(const char* canvas)
+  {
+    try
+    {
+      GetViewport(canvas)->FlipY();
+    }
+    EXTERN_CATCH_EXCEPTIONS;
+  }  
+  
+
+  EMSCRIPTEN_KEEPALIVE
   void SetSoftwareRendering(int softwareRendering)
   {
     softwareRendering_ = softwareRendering;
--- a/OrthancStone/Sources/Scene2D/TextureBaseSceneLayer.cpp	Mon Aug 17 13:25:54 2020 +0200
+++ b/OrthancStone/Sources/Scene2D/TextureBaseSceneLayer.cpp	Mon Aug 17 16:10:00 2020 +0200
@@ -47,6 +47,8 @@
     pixelSpacingY_ = other.pixelSpacingY_;
     angle_ = other.angle_;
     isLinearInterpolation_ = other.isLinearInterpolation_;
+    flipX_ = other.flipX_;
+    flipY_ = other.flipY_;
   }
 
 
@@ -57,6 +59,8 @@
     pixelSpacingY_(1),
     angle_(0),
     isLinearInterpolation_(false),
+    flipX_(false),
+    flipY_(false),
     revision_(0)
   {
     if (pixelSpacingX_ <= 0 ||
@@ -107,6 +111,20 @@
   }
     
 
+  void TextureBaseSceneLayer::SetFlipX(bool flip)
+  {
+    flipX_ = flip;
+    IncrementRevision();
+  }
+  
+    
+  void TextureBaseSceneLayer::SetFlipY(bool flip)
+  {
+    flipY_ = flip;
+    IncrementRevision();
+  }
+    
+
   const Orthanc::ImageAccessor& TextureBaseSceneLayer::GetTexture() const
   {
     if (!HasTexture())
@@ -123,11 +141,21 @@
   
   AffineTransform2D TextureBaseSceneLayer::GetTransform() const
   {
+    unsigned int width = 0;
+    unsigned int height = 0;
+
+    if (texture_.get() != NULL)
+    {
+      width = texture_->GetWidth();
+      height = texture_->GetHeight();
+    }
+    
     return AffineTransform2D::Combine(
       AffineTransform2D::CreateOffset(originX_, originY_),
       AffineTransform2D::CreateRotation(angle_),
       AffineTransform2D::CreateScaling(pixelSpacingX_, pixelSpacingY_),
-      AffineTransform2D::CreateOffset(-0.5, -0.5));
+      AffineTransform2D::CreateOffset(-0.5, -0.5),
+      AffineTransform2D::CreateFlip(flipX_, flipY_, width, height));
   }
 
   
--- a/OrthancStone/Sources/Scene2D/TextureBaseSceneLayer.h	Mon Aug 17 13:25:54 2020 +0200
+++ b/OrthancStone/Sources/Scene2D/TextureBaseSceneLayer.h	Mon Aug 17 16:10:00 2020 +0200
@@ -39,6 +39,8 @@
     double                                 pixelSpacingY_;
     double                                 angle_;
     bool                                   isLinearInterpolation_;
+    bool                                   flipX_;
+    bool                                   flipY_;
     uint64_t                               revision_;
 
   protected:
@@ -65,6 +67,10 @@
     void SetAngle(double angle);
 
     void SetLinearInterpolation(bool isLinearInterpolation);
+
+    void SetFlipX(bool flip);
+    
+    void SetFlipY(bool flip);
     
     double GetOriginX() const
     {
@@ -101,6 +107,16 @@
       return (texture_.get() != NULL);
     }
 
+    bool IsFlipX() const
+    {
+      return flipX_;
+    }
+
+    bool IsFlipY() const
+    {
+      return flipY_;
+    }
+
     const Orthanc::ImageAccessor& GetTexture() const;
 
     AffineTransform2D GetTransform() const;
--- a/OrthancStone/Sources/Toolbox/AffineTransform2D.cpp	Mon Aug 17 13:25:54 2020 +0200
+++ b/OrthancStone/Sources/Toolbox/AffineTransform2D.cpp	Mon Aug 17 16:10:00 2020 +0200
@@ -268,4 +268,19 @@
     
     return t;
   }
+
+  
+  AffineTransform2D AffineTransform2D::CreateFlip(bool flipX,
+                                                  bool flipY,
+                                                  unsigned int width,
+                                                  unsigned int height)
+  {
+    AffineTransform2D t;
+    t.matrix_(0, 0) = (flipX ? -1 : 1);
+    t.matrix_(0, 2) = (flipX ? width : 0);
+    t.matrix_(1, 1) = (flipY ? -1 : 1);
+    t.matrix_(1, 2) = (flipY ? height : 0);
+
+    return t;
+  }
 }
--- a/OrthancStone/Sources/Toolbox/AffineTransform2D.h	Mon Aug 17 13:25:54 2020 +0200
+++ b/OrthancStone/Sources/Toolbox/AffineTransform2D.h	Mon Aug 17 16:10:00 2020 +0200
@@ -99,5 +99,10 @@
 
     static AffineTransform2D CreateOpenGLClipspace(unsigned int canvasWidth,
                                                    unsigned int canvasHeight);
+
+    static AffineTransform2D CreateFlip(bool flipX,
+                                        bool flipY,
+                                        unsigned int width,
+                                        unsigned int height);
   };
 }