diff Framework/Radiography/RadiographyScene.h @ 408:6834c236b36d

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 12 Nov 2018 14:52:10 +0100
parents
children 99c9b3238008
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Radiography/RadiographyScene.h	Mon Nov 12 14:52:10 2018 +0100
@@ -0,0 +1,325 @@
+/**
+ * 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 "../Toolbox/Extent2D.h"
+#include "../Toolbox/LinearAlgebra.h"
+#include "../Toolbox/OrthancApiClient.h"
+#include "../Viewport/CairoContext.h"
+
+
+namespace OrthancStone
+{
+  class RadiographyScene :
+    public IObserver,
+    public IObservable
+  {
+  public:
+    typedef OriginMessage<MessageType_Widget_GeometryChanged, RadiographyScene> GeometryChangedMessage;
+    typedef OriginMessage<MessageType_Widget_ContentChanged, RadiographyScene> ContentChangedMessage;
+
+    enum Corner
+    {
+      Corner_TopLeft,
+      Corner_TopRight,
+      Corner_BottomLeft,
+      Corner_BottomRight
+    };
+
+    class Layer : public boost::noncopyable
+    {
+      friend class RadiographyScene;
+      
+    private:
+      size_t        index_;
+      bool          hasSize_;
+      unsigned int  width_;
+      unsigned int  height_;
+      bool          hasCrop_;
+      unsigned int  cropX_;
+      unsigned int  cropY_;
+      unsigned int  cropWidth_;
+      unsigned int  cropHeight_;
+      Matrix        transform_;
+      Matrix        transformInverse_;
+      double        pixelSpacingX_;
+      double        pixelSpacingY_;
+      double        panX_;
+      double        panY_;
+      double        angle_;
+      bool          resizeable_;
+
+
+    protected:
+      const Matrix& GetTransform() const
+      {
+        return transform_;
+      }
+
+
+    private:
+      void UpdateTransform();
+      
+      void AddToExtent(Extent2D& extent,
+                       double x,
+                       double y) const;
+
+      void GetCornerInternal(double& x,
+                             double& y,
+                             Corner corner,
+                             unsigned int cropX,
+                             unsigned int cropY,
+                             unsigned int cropWidth,
+                             unsigned int cropHeight) const;
+
+      void SetIndex(size_t index)
+      {
+        index_ = index;
+      }
+      
+      bool Contains(double x,
+                    double y) const;
+      
+      void DrawBorders(CairoContext& context,
+                       double zoom);
+
+    public:
+      Layer();
+
+      virtual ~Layer()
+      {
+      }
+
+      size_t GetIndex() const
+      {
+        return index_;
+      }
+
+      void ResetCrop()
+      {
+        hasCrop_ = false;
+      }
+
+      void SetCrop(unsigned int x,
+                   unsigned int y,
+                   unsigned int width,
+                   unsigned int height);
+
+      void GetCrop(unsigned int& x,
+                   unsigned int& y,
+                   unsigned int& width,
+                   unsigned int& height) const;
+
+      void SetAngle(double angle);
+
+      double GetAngle() const
+      {
+        return angle_;
+      }
+
+      void SetSize(unsigned int width,
+                   unsigned int height);
+
+      unsigned int GetWidth() const
+      {
+        return width_;
+      }        
+
+      unsigned int GetHeight() const
+      {
+        return height_;
+      }       
+
+      Extent2D GetExtent() const;
+
+      bool GetPixel(unsigned int& imageX,
+                    unsigned int& imageY,
+                    double sceneX,
+                    double sceneY) const;
+
+      void SetPan(double x,
+                  double y);
+
+      void SetPixelSpacing(double x,
+                           double y);
+
+      double GetPixelSpacingX() const
+      {
+        return pixelSpacingX_;
+      }   
+
+      double GetPixelSpacingY() const
+      {
+        return pixelSpacingY_;
+      }   
+
+      double GetPanX() const
+      {
+        return panX_;
+      }
+
+      double GetPanY() const
+      {
+        return panY_;
+      }
+
+      void GetCenter(double& centerX,
+                     double& centerY) const;
+
+      void GetCorner(double& x /* out */,
+                     double& y /* out */,
+                     Corner corner) const;
+      
+      bool LookupCorner(Corner& corner /* out */,
+                        double x,
+                        double y,
+                        double zoom,
+                        double viewportDistance) const;
+
+      bool IsResizeable() const
+      {
+        return resizeable_;
+      }
+
+      void SetResizeable(bool resizeable)
+      {
+        resizeable_ = resizeable;
+      }
+
+      virtual bool GetDefaultWindowing(float& center,
+                                       float& width) const = 0;
+
+      virtual void Render(Orthanc::ImageAccessor& buffer,
+                          const Matrix& viewTransform,
+                          ImageInterpolation interpolation) const = 0;
+
+      virtual bool GetRange(float& minValue,
+                            float& maxValue) const = 0;
+    }; 
+
+
+    class LayerAccessor : public boost::noncopyable
+    {
+    private:
+      RadiographyScene&  scene_;
+      size_t             index_;
+      Layer*             layer_;
+
+    public:
+      LayerAccessor(RadiographyScene& scene,
+                    size_t index);
+
+      LayerAccessor(RadiographyScene& scene,
+                    double x,
+                    double y);
+
+      void Invalidate()
+      {
+        layer_ = NULL;
+      }
+
+      bool IsValid() const
+      {
+        return layer_ != NULL;
+      }
+
+      RadiographyScene& GetScene() const;
+
+      size_t GetIndex() const;
+
+      Layer& GetLayer() const;
+    };
+
+
+  private:
+    class AlphaLayer;    
+    class DicomLayer;
+
+    typedef std::map<size_t, Layer*>  Layers;
+        
+    OrthancApiClient&  orthanc_;
+    size_t             countLayers_;
+    bool               hasWindowing_;
+    float              windowingCenter_;
+    float              windowingWidth_;
+    Layers             layers_;
+
+    Layer& RegisterLayer(Layer* layer);
+
+    void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message);
+
+    void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message);
+    
+    void OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+  public:
+    RadiographyScene(MessageBroker& broker,
+                     OrthancApiClient& orthanc);
+    
+    virtual ~RadiographyScene();
+
+    bool GetWindowing(float& center,
+                      float& width) const;
+
+    void GetWindowingWithDefault(float& center,
+                                 float& width) const;
+
+    void SetWindowing(float center,
+                      float width);
+
+    Layer& LoadText(const Orthanc::Font& font,
+                    const std::string& utf8);
+    
+    Layer& LoadTestBlock(unsigned int width,
+                         unsigned int height);
+    
+    Layer& LoadDicomFrame(const std::string& instance,
+                          unsigned int frame,
+                          bool httpCompression);
+
+    Extent2D GetSceneExtent() const;
+
+    void Render(Orthanc::ImageAccessor& buffer,
+                const Matrix& viewTransform,
+                ImageInterpolation interpolation) const;
+
+    bool LookupLayer(size_t& index /* out */,
+                     double x,
+                     double y) const;
+    
+    void DrawBorder(CairoContext& context,
+                    unsigned int layer,
+                    double zoom);
+
+    void GetRange(float& minValue,
+                  float& maxValue) const;
+
+    // Export using PAM is faster than using PNG, but requires Orthanc
+    // core >= 1.4.3
+    void ExportDicom(const Orthanc::DicomMap& dicom,
+                     double pixelSpacingX,
+                     double pixelSpacingY,
+                     bool invert,
+                     ImageInterpolation interpolation,
+                     bool usePam);
+  };
+}