changeset 2197:874ff09fbe89

refactoring by introducing OrientationMarkersSource
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 19 Apr 2025 11:10:32 +0200
parents 1c5d4541cfb5
children 5a16051c7f3c
files Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp
diffstat 1 files changed, 123 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Sat Apr 19 10:54:40 2025 +0200
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Sat Apr 19 11:10:32 2025 +0200
@@ -101,6 +101,7 @@
 
 static const double PI = boost::math::constants::pi<double>();
 
+static const int LAYER_ORIENTATION_MARKERS = 2;
 static const int LAYER_ANNOTATIONS_OSIRIX = 4;
 
 
@@ -1784,6 +1785,7 @@
 
 
 
+// WARNING: This class can be shared by multiple viewports
 class ILayerSource : public boost::noncopyable
 {
 public:
@@ -1793,69 +1795,15 @@
 
   virtual int GetDepth() const = 0;
 
-  virtual OrthancStone::ISceneLayer* Create(const std::string& studyInstanceUid,
-                                            const std::string& seriesInstanceUid,
-                                            const std::string& sopInstanceUid,
+  virtual OrthancStone::ISceneLayer* Create(const Orthanc::ImageAccessor& frame,
+                                            const OrthancStone::DicomInstanceParameters& instance,
                                             unsigned int frameNumber,
+                                            double pixelSpacingX,
+                                            double pixelSpacingY,
                                             const OrthancStone::CoordinateSystem3D& plane) = 0;
 };
 
 
-class OsiriXLayerSource : public ILayerSource
-{
-private:
-  int depth_;
-
-  // The coordinates of OsiriX annotations are expressed in 3D world coordinates
-  OrthancStone::OsiriX::CollectionOfAnnotations  annotations_;
-
-public:
-  OsiriXLayerSource(int depth) :
-    depth_(depth)
-  {
-  }
-
-  OrthancStone::OsiriX::CollectionOfAnnotations& GetAnnotations()
-  {
-    return annotations_;
-  }
-
-  virtual int GetDepth() const ORTHANC_OVERRIDE
-  {
-    return depth_;
-  }
-
-  virtual OrthancStone::ISceneLayer* Create(const std::string& studyInstanceUid,
-                                            const std::string& seriesInstanceUid,
-                                            const std::string& sopInstanceUid,
-                                            unsigned int frameNumber,
-                                            const OrthancStone::CoordinateSystem3D& plane) ORTHANC_OVERRIDE
-  {
-    std::set<size_t> a;
-    annotations_.LookupSopInstanceUid(a, sopInstanceUid);
-    if (plane.IsValid() &&
-        !a.empty())
-    {
-      std::unique_ptr<OrthancStone::MacroSceneLayer> layer(new OrthancStone::MacroSceneLayer);
-      // layer->Reserve(a.size());
-
-      OrthancStone::OsiriXLayerFactory factory;
-      factory.SetColor(0, 255, 0);
-
-      for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it)
-      {
-        const OrthancStone::OsiriX::Annotation& annotation = annotations_.GetAnnotation(*it);
-        layer->AddLayer(factory.Create(annotation, plane));
-      }
-
-      return layer.release();
-    }
-
-    return NULL;
-  }
-};
-
-
 class LayersHolder : public boost::noncopyable
 {
 private:
@@ -1962,7 +1910,6 @@
 private:
   static const int LAYER_TEXTURE = 0;
   static const int LAYER_OVERLAY = 1;
-  static const int LAYER_ORIENTATION_MARKERS = 2;
   static const int LAYER_REFERENCE_LINES = 3;
   static const int LAYER_ANNOTATIONS_STONE = 5;
 
@@ -2649,52 +2596,12 @@
 
     StoneAnnotationsRegistry::GetInstance().Load(*stoneAnnotations_, instance.GetSopInstanceUid(), frameIndex);
 
-    // Orientation markers, new in Stone Web viewer 2.4
-    std::unique_ptr<OrthancStone::MacroSceneLayer>  orientationMarkers;
-
-    if (instance.GetGeometry().IsValid())
-    {
-      orientationMarkers.reset(new OrthancStone::MacroSceneLayer);
-
-      std::string top, bottom, left, right;
-      instance.GetGeometry().GetOrientationMarkers(top, bottom, left, right);
-
-      std::unique_ptr<OrthancStone::TextSceneLayer> text;
-
-      text.reset(new OrthancStone::TextSceneLayer);
-      text->SetText(top);
-      text->SetPosition(pixelSpacingX * static_cast<double>(frame.GetWidth()) / 2.0, 0);
-      text->SetAnchor(OrthancStone::BitmapAnchor_TopCenter);
-      orientationMarkers->AddLayer(text.release());
-
-      text.reset(new OrthancStone::TextSceneLayer);
-      text->SetText(bottom);
-      text->SetPosition(pixelSpacingX * static_cast<double>(frame.GetWidth()) / 2.0,
-                        pixelSpacingY * static_cast<double>(frame.GetHeight()));
-      text->SetAnchor(OrthancStone::BitmapAnchor_BottomCenter);
-      orientationMarkers->AddLayer(text.release());
-
-      text.reset(new OrthancStone::TextSceneLayer);
-      text->SetText(left);
-      text->SetPosition(0, pixelSpacingY * static_cast<double>(frame.GetHeight()) / 2.0);
-      text->SetAnchor(OrthancStone::BitmapAnchor_CenterLeft);
-      orientationMarkers->AddLayer(text.release());
-
-      text.reset(new OrthancStone::TextSceneLayer);
-      text->SetText(right);
-      text->SetPosition(pixelSpacingX * static_cast<double>(frame.GetWidth()),
-                        pixelSpacingY * static_cast<double>(frame.GetHeight()) / 2.0);
-      text->SetAnchor(OrthancStone::BitmapAnchor_CenterRight);
-      orientationMarkers->AddLayer(text.release());
-    }
-
-
     LayersHolder holder;
 
     for (std::list<ILayerSource*>::const_iterator it = layerSources_.begin(); it != layerSources_.end(); ++it)
     {
       assert(*it != NULL);
-      holder.AddLayer((*it)->GetDepth(), (*it)->Create(instance.GetStudyInstanceUid(), instance.GetSeriesInstanceUid(), instance.GetSopInstanceUid(), frameIndex, plane));
+      holder.AddLayer((*it)->GetDepth(), (*it)->Create(frame, instance, frameIndex, pixelSpacingX, pixelSpacingY, plane));
     }
 
     {
@@ -2715,15 +2622,6 @@
         scene.DeleteLayer(LAYER_OVERLAY);
       }
 
-      if (orientationMarkers.get() != NULL)
-      {
-        scene.SetLayer(LAYER_ORIENTATION_MARKERS, orientationMarkers.release());
-      }
-      else
-      {
-        scene.DeleteLayer(LAYER_ORIENTATION_MARKERS);
-      }
-
       stoneAnnotations_->Render(scene);  // Necessary for "FitContent()" to work
 
       if (fitNextContent_)
@@ -3892,12 +3790,125 @@
 
 
 
+class OrientationMarkersSource : public ILayerSource
+{
+public:
+  virtual int GetDepth() const ORTHANC_OVERRIDE
+  {
+    return LAYER_ORIENTATION_MARKERS;
+  }
+
+  virtual OrthancStone::ISceneLayer* Create(const Orthanc::ImageAccessor& frame,
+                                            const OrthancStone::DicomInstanceParameters& instance,
+                                            unsigned int frameNumber,
+                                            double pixelSpacingX,
+                                            double pixelSpacingY,
+                                            const OrthancStone::CoordinateSystem3D& plane) ORTHANC_OVERRIDE
+  {
+    if (instance.GetGeometry().IsValid())
+    {
+      std::unique_ptr<OrthancStone::MacroSceneLayer> layer(new OrthancStone::MacroSceneLayer);
+
+      std::string top, bottom, left, right;
+      instance.GetGeometry().GetOrientationMarkers(top, bottom, left, right);
+
+      std::unique_ptr<OrthancStone::TextSceneLayer> text;
+
+      text.reset(new OrthancStone::TextSceneLayer);
+      text->SetText(top);
+      text->SetPosition(pixelSpacingX * static_cast<double>(frame.GetWidth()) / 2.0, 0);
+      text->SetAnchor(OrthancStone::BitmapAnchor_TopCenter);
+      layer->AddLayer(text.release());
+
+      text.reset(new OrthancStone::TextSceneLayer);
+      text->SetText(bottom);
+      text->SetPosition(pixelSpacingX * static_cast<double>(frame.GetWidth()) / 2.0,
+                        pixelSpacingY * static_cast<double>(frame.GetHeight()));
+      text->SetAnchor(OrthancStone::BitmapAnchor_BottomCenter);
+      layer->AddLayer(text.release());
+
+      text.reset(new OrthancStone::TextSceneLayer);
+      text->SetText(left);
+      text->SetPosition(0, pixelSpacingY * static_cast<double>(frame.GetHeight()) / 2.0);
+      text->SetAnchor(OrthancStone::BitmapAnchor_CenterLeft);
+      layer->AddLayer(text.release());
+
+      text.reset(new OrthancStone::TextSceneLayer);
+      text->SetText(right);
+      text->SetPosition(pixelSpacingX * static_cast<double>(frame.GetWidth()),
+                        pixelSpacingY * static_cast<double>(frame.GetHeight()) / 2.0);
+      text->SetAnchor(OrthancStone::BitmapAnchor_CenterRight);
+      layer->AddLayer(text.release());
+
+      return layer.release();
+    }
+    else
+    {
+      return NULL;
+    }
+  }
+};
+
+
+class OsiriXLayerSource : public ILayerSource
+{
+private:
+  // The coordinates of OsiriX annotations are expressed in 3D world coordinates
+  OrthancStone::OsiriX::CollectionOfAnnotations  annotations_;
+
+public:
+  OrthancStone::OsiriX::CollectionOfAnnotations& GetAnnotations()
+  {
+    return annotations_;
+  }
+
+  virtual int GetDepth() const ORTHANC_OVERRIDE
+  {
+    return LAYER_ANNOTATIONS_OSIRIX;
+  }
+
+  virtual OrthancStone::ISceneLayer* Create(const Orthanc::ImageAccessor& frame,
+                                            const OrthancStone::DicomInstanceParameters& instance,
+                                            unsigned int frameNumber,
+                                            double pixelSpacingX,
+                                            double pixelSpacingY,
+                                            const OrthancStone::CoordinateSystem3D& plane) ORTHANC_OVERRIDE
+  {
+    std::set<size_t> a;
+    annotations_.LookupSopInstanceUid(a, instance.GetSopInstanceUid());
+    if (plane.IsValid() &&
+        !a.empty())
+    {
+      std::unique_ptr<OrthancStone::MacroSceneLayer> layer(new OrthancStone::MacroSceneLayer);
+      // layer->Reserve(a.size());
+
+      OrthancStone::OsiriXLayerFactory factory;
+      factory.SetColor(0, 255, 0);
+
+      for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it)
+      {
+        const OrthancStone::OsiriX::Annotation& annotation = annotations_.GetAnnotation(*it);
+        layer->AddLayer(factory.Create(annotation, plane));
+      }
+
+      return layer.release();
+    }
+
+    return NULL;
+  }
+};
+
+
+
 typedef std::map<std::string, boost::shared_ptr<ViewerViewport> >  Viewports;
 
 static Viewports allViewports_;
 static bool showReferenceLines_ = true;
 static boost::shared_ptr<OsiriXLayerSource>  osiriXLayerSource_;
 
+// Orientation markers, new in Stone Web viewer 2.4
+static boost::shared_ptr<OrientationMarkersSource>  orientationMarkersSource_;
+
 
 static void UpdateReferenceLines()
 {
@@ -4227,6 +4238,7 @@
     viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_);
     viewport->AcquireObserver(new WebAssemblyObserver);
     viewport->AddLayerSource(*osiriXLayerSource_);
+    viewport->AddLayerSource(*orientationMarkersSource_);
     allViewports_[canvas] = viewport;
     return viewport;
   }
@@ -4262,7 +4274,8 @@
     
     framesCache_.reset(new FramesCache);
     instancesCache_.reset(new InstancesCache);
-    osiriXLayerSource_.reset(new OsiriXLayerSource(LAYER_ANNOTATIONS_OSIRIX));
+    osiriXLayerSource_.reset(new OsiriXLayerSource);
+    orientationMarkersSource_.reset(new OrientationMarkersSource);
 
     for (size_t i = 0; pluginsInitializers_[i] != NULL; i++)
     {