changeset 2380:6a631b1d18ae refactoring

removed link to IViewport in MeasureTool
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 09 Oct 2026 16:33:43 +0200
parents badae7b22831
children d27f022ac3ec
files OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.cpp OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.h OrthancStone/Sources/Scene2DViewport/LineMeasureTool.cpp OrthancStone/Sources/Scene2DViewport/LineMeasureTool.h OrthancStone/Sources/Scene2DViewport/MeasureTool.cpp OrthancStone/Sources/Scene2DViewport/MeasureTool.h OrthancStone/Sources/Scene2DViewport/ViewportController.cpp OrthancStone/Sources/Scene2DViewport/ViewportController.h
diffstat 8 files changed, 231 insertions(+), 310 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.cpp	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.cpp	Fri Oct 09 16:33:43 2026 +0200
@@ -53,7 +53,7 @@
   public:
     Tracker(const boost::shared_ptr<AngleMeasureTool>& tool,
             bool isCreation,
-            const Scene2D& scene,
+            const Scene2D& scene,   // TODO Refactoring - The scene can be retrieved from the tool
             const PointerEvent& e) :
       tool_(tool),
       originalClickPosition_(e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform())),
@@ -169,9 +169,8 @@
 
   // the params in the LayerHolder ctor specify the number of polyline and text
   // layers
-  AngleMeasureTool::AngleMeasureTool(boost::weak_ptr<IViewport> viewport,
-                                     const boost::shared_ptr<ViewportController>& controller) :
-    MeasureTool(viewport, controller)
+  AngleMeasureTool::AngleMeasureTool(const boost::shared_ptr<ViewportController>& controller) :
+    MeasureTool(controller)
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
     , layerHolder_(boost::shared_ptr<LayerHolder>(new LayerHolder(1, 5)))
 #else
@@ -181,10 +180,9 @@
   {
   }
 
-  boost::shared_ptr<AngleMeasureTool> AngleMeasureTool::Create(boost::weak_ptr<IViewport> viewport,
-                                                               const boost::shared_ptr<ViewportController>& controller)
+  boost::shared_ptr<AngleMeasureTool> AngleMeasureTool::Create(const boost::shared_ptr<ViewportController>& controller)
   {
-    boost::shared_ptr<AngleMeasureTool> obj(new AngleMeasureTool(viewport, controller));
+    boost::shared_ptr<AngleMeasureTool> obj(new AngleMeasureTool(controller));
     obj->MeasureTool::PostConstructor();
     obj->RefreshScene();
     return obj;
@@ -200,12 +198,10 @@
 
   void AngleMeasureTool::RemoveFromScene()
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-
-    if (layerHolder_->AreLayersCreated() && IsSceneAlive())
+    if (layerHolder_->AreLayersCreated())
     {
-      layerHolder_->DeleteLayers(lock->GetController().GetScene());
-      lock->Invalidate();
+      layerHolder_->DeleteLayers(GetController().GetScene());
+      GetController().InvalidateViewport();
     }
   }
 
@@ -329,10 +325,7 @@
   IFlexiblePointerTracker* AngleMeasureTool::CreateEditionTracker(bool isCreation,
                                                                   const PointerEvent& e)
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-
-    ViewportController& controller = lock->GetController();
-    const Scene2D& scene = controller.GetScene();
+    const Scene2D& scene = GetController().GetScene();
     ScenePoint2D scenePos = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
 
     if (!HitTest(scene, scenePos))
@@ -353,194 +346,190 @@
   
   void AngleMeasureTool::RefreshScene()
   {
-    if (IsSceneAlive())
+    Scene2D& scene = GetController().GetScene();
+
+    if (IsEnabled())
     {
-      std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-      ViewportController& controller = lock->GetController();
-      Scene2D& scene = controller.GetScene();
+      layerHolder_->CreateLayersIfNeeded(scene);
 
-      if (IsEnabled())
       {
-        layerHolder_->CreateLayersIfNeeded(scene);
-
+        // Fill the polyline layer with the measurement lines
+        PolylineSceneLayer* polylineLayer = layerHolder_->GetPolylineLayer(scene, 0);
+        if (polylineLayer)
         {
-          // Fill the polyline layer with the measurement lines
-          PolylineSceneLayer* polylineLayer = layerHolder_->GetPolylineLayer(scene, 0);
-          if (polylineLayer)
-          {
-            polylineLayer->ClearAllChains();
+          polylineLayer->ClearAllChains();
+
+          const Color color(TOOL_ANGLE_LINES_COLOR_RED, 
+                            TOOL_ANGLE_LINES_COLOR_GREEN, 
+                            TOOL_ANGLE_LINES_COLOR_BLUE);
+
+          const Color highlightColor(TOOL_ANGLE_LINES_HL_COLOR_RED, 
+                                     TOOL_ANGLE_LINES_HL_COLOR_GREEN, 
+                                     TOOL_ANGLE_LINES_HL_COLOR_BLUE);
 
-            const Color color(TOOL_ANGLE_LINES_COLOR_RED, 
-                              TOOL_ANGLE_LINES_COLOR_GREEN, 
-                              TOOL_ANGLE_LINES_COLOR_BLUE);
+          // sides
+          {
+            {
+              PolylineSceneLayer::Chain chain;
+              chain.push_back(side1End_);
+              chain.push_back(center_);
 
-            const Color highlightColor(TOOL_ANGLE_LINES_HL_COLOR_RED, 
-                                       TOOL_ANGLE_LINES_HL_COLOR_GREEN, 
-                                       TOOL_ANGLE_LINES_HL_COLOR_BLUE);
-
-            // sides
-            {
+              if ((angleHighlightArea_ == AngleHighlightArea_Side1) ||
+                  (angleHighlightArea_ == AngleHighlightArea_Side2))
               {
-                PolylineSceneLayer::Chain chain;
-                chain.push_back(side1End_);
-                chain.push_back(center_);
-
-                if ((angleHighlightArea_ == AngleHighlightArea_Side1) ||
-                    (angleHighlightArea_ == AngleHighlightArea_Side2))
-                {
-                  polylineLayer->AddChain(chain, false, highlightColor);
-                } 
-                else
-                {
-                  polylineLayer->AddChain(chain, false, color);
-                }
+                polylineLayer->AddChain(chain, false, highlightColor);
+              } 
+              else
+              {
+                polylineLayer->AddChain(chain, false, color);
               }
+            }
+            {
+              PolylineSceneLayer::Chain chain;
+              chain.push_back(side2End_);
+              chain.push_back(center_);
+              if ((angleHighlightArea_ == AngleHighlightArea_Side1) ||
+                  (angleHighlightArea_ == AngleHighlightArea_Side2))
               {
-                PolylineSceneLayer::Chain chain;
-                chain.push_back(side2End_);
-                chain.push_back(center_);
-                if ((angleHighlightArea_ == AngleHighlightArea_Side1) ||
-                    (angleHighlightArea_ == AngleHighlightArea_Side2))
-                {
-                  polylineLayer->AddChain(chain, false, highlightColor);
-                }
-                else
-                {
-                  polylineLayer->AddChain(chain, false, color);
-                }
+                polylineLayer->AddChain(chain, false, highlightColor);
+              }
+              else
+              {
+                polylineLayer->AddChain(chain, false, color);
               }
             }
+          }
 
-            // Create the handles
+          // Create the handles
+          {
             {
-              {
-                PolylineSceneLayer::Chain chain;
-                //TODO: take DPI into account
-                AddSquare(chain, controller.GetScene(), side1End_, GetHandleSideLengthS(controller.GetScene()));
-              
-                if (angleHighlightArea_ == AngleHighlightArea_Side1End)
-                  polylineLayer->AddChain(chain, true, highlightColor);
-                else
-                  polylineLayer->AddChain(chain, true, color);
+              PolylineSceneLayer::Chain chain;
+              //TODO: take DPI into account
+              AddSquare(chain, scene, side1End_, GetHandleSideLengthS(scene));
               
-              }
-              {
-                PolylineSceneLayer::Chain chain;
-                //TODO: take DPI into account
-                AddSquare(chain, controller.GetScene(), side2End_, GetHandleSideLengthS(controller.GetScene()));
-
-                if (angleHighlightArea_ == AngleHighlightArea_Side2End)
-                  polylineLayer->AddChain(chain, true, highlightColor);
-                else
-                  polylineLayer->AddChain(chain, true, color);
-              }
+              if (angleHighlightArea_ == AngleHighlightArea_Side1End)
+                polylineLayer->AddChain(chain, true, highlightColor);
+              else
+                polylineLayer->AddChain(chain, true, color);
+              
             }
-
-            // Create the arc
             {
               PolylineSceneLayer::Chain chain;
+              //TODO: take DPI into account
+              AddSquare(chain, scene, side2End_, GetHandleSideLengthS(scene));
 
-              AddShortestArc(chain, side1End_, center_, side2End_, GetAngleToolArcRadiusS(controller.GetScene()));
-              if (angleHighlightArea_ == AngleHighlightArea_Center)
-                polylineLayer->AddChain(chain, false, highlightColor);
+              if (angleHighlightArea_ == AngleHighlightArea_Side2End)
+                polylineLayer->AddChain(chain, true, highlightColor);
               else
-                polylineLayer->AddChain(chain, false, color);
+                polylineLayer->AddChain(chain, true, color);
             }
           }
+
+          // Create the arc
+          {
+            PolylineSceneLayer::Chain chain;
+
+            AddShortestArc(chain, side1End_, center_, side2End_, GetAngleToolArcRadiusS(scene));
+            if (angleHighlightArea_ == AngleHighlightArea_Center)
+              polylineLayer->AddChain(chain, false, highlightColor);
+            else
+              polylineLayer->AddChain(chain, false, color);
+          }
         }
-        {
-          // Set the text layer
+      }
+      {
+        // Set the text layer
 
-          double p1cAngle = atan2(
-            side1End_.GetY() - center_.GetY(),
-            side1End_.GetX() - center_.GetX());
+        double p1cAngle = atan2(
+          side1End_.GetY() - center_.GetY(),
+          side1End_.GetX() - center_.GetX());
 
-          double p2cAngle = atan2(
-            side2End_.GetY() - center_.GetY(),
-            side2End_.GetX() - center_.GetX());
+        double p2cAngle = atan2(
+          side2End_.GetY() - center_.GetY(),
+          side2End_.GetX() - center_.GetX());
 
-          double delta = NormalizeAngle(p2cAngle - p1cAngle);
-          double theta = p1cAngle + delta / 2;
+        double delta = NormalizeAngle(p2cAngle - p1cAngle);
+        double theta = p1cAngle + delta / 2;
 
-          double ox = GetAngleTopTextLabelDistanceS(controller.GetScene()) * cos(theta);
-          double oy = GetAngleTopTextLabelDistanceS(controller.GetScene()) * sin(theta);
+        double ox = GetAngleTopTextLabelDistanceS(scene) * cos(theta);
+        double oy = GetAngleTopTextLabelDistanceS(scene) * sin(theta);
 
-          double pointX = center_.GetX() + ox;
-          double pointY = center_.GetY() + oy;
+        double pointX = center_.GetX() + ox;
+        double pointY = center_.GetY() + oy;
 
-          char buf[64];
-          double angleDeg = std::abs(RadiansToDegrees(delta));
+        char buf[64];
+        double angleDeg = std::abs(RadiansToDegrees(delta));
 
-          // http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=00B0&mode=hex
-          sprintf(buf, "%0.02f\xc2\xb0", angleDeg);
+        // http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=00B0&mode=hex
+        sprintf(buf, "%0.02f\xc2\xb0", angleDeg);
 
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
-          SetTextLayerOutlineProperties(
-            scene, layerHolder_, buf, ScenePoint2D(pointX, pointY), 0);
+        SetTextLayerOutlineProperties(
+          scene, layerHolder_, buf, ScenePoint2D(pointX, pointY), 0);
 #else
-          SetTextLayerProperties(
-            scene, layerHolder_, buf, ScenePoint2D(pointX, pointY) , 0);
+        SetTextLayerProperties(
+          scene, layerHolder_, buf, ScenePoint2D(pointX, pointY) , 0);
 #endif
 
 #if 0
-          // TODO:make it togglable
-          bool enableInfoDisplay = true;
-          if (enableInfoDisplay)
-          {
-            TrackerSample_SetInfoDisplayMessage("center_.GetX()",
-                                                boost::lexical_cast<std::string>(center_.GetX()));
+        // TODO:make it togglable
+        bool enableInfoDisplay = true;
+        if (enableInfoDisplay)
+        {
+          TrackerSample_SetInfoDisplayMessage("center_.GetX()",
+                                              boost::lexical_cast<std::string>(center_.GetX()));
 
-            TrackerSample_SetInfoDisplayMessage("center_.GetY()",
-                                                boost::lexical_cast<std::string>(center_.GetY()));
+          TrackerSample_SetInfoDisplayMessage("center_.GetY()",
+                                              boost::lexical_cast<std::string>(center_.GetY()));
 
-            TrackerSample_SetInfoDisplayMessage("side1End_.GetX()",
-                                                boost::lexical_cast<std::string>(side1End_.GetX()));
+          TrackerSample_SetInfoDisplayMessage("side1End_.GetX()",
+                                              boost::lexical_cast<std::string>(side1End_.GetX()));
 
-            TrackerSample_SetInfoDisplayMessage("side1End_.GetY()",
-                                                boost::lexical_cast<std::string>(side1End_.GetY()));
+          TrackerSample_SetInfoDisplayMessage("side1End_.GetY()",
+                                              boost::lexical_cast<std::string>(side1End_.GetY()));
 
-            TrackerSample_SetInfoDisplayMessage("side2End_.GetX()",
-                                                boost::lexical_cast<std::string>(side2End_.GetX()));
+          TrackerSample_SetInfoDisplayMessage("side2End_.GetX()",
+                                              boost::lexical_cast<std::string>(side2End_.GetX()));
 
-            TrackerSample_SetInfoDisplayMessage("side2End_.GetY()",
-                                                boost::lexical_cast<std::string>(side2End_.GetY()));
+          TrackerSample_SetInfoDisplayMessage("side2End_.GetY()",
+                                              boost::lexical_cast<std::string>(side2End_.GetY()));
 
-            TrackerSample_SetInfoDisplayMessage("p1cAngle (deg)",
-                                                boost::lexical_cast<std::string>(RadiansToDegrees(p1cAngle)));
+          TrackerSample_SetInfoDisplayMessage("p1cAngle (deg)",
+                                              boost::lexical_cast<std::string>(RadiansToDegrees(p1cAngle)));
 
-            TrackerSample_SetInfoDisplayMessage("delta (deg)",
-                                                boost::lexical_cast<std::string>(RadiansToDegrees(delta)));
+          TrackerSample_SetInfoDisplayMessage("delta (deg)",
+                                              boost::lexical_cast<std::string>(RadiansToDegrees(delta)));
 
-            TrackerSample_SetInfoDisplayMessage("theta (deg)",
-                                                boost::lexical_cast<std::string>(RadiansToDegrees(theta)));
+          TrackerSample_SetInfoDisplayMessage("theta (deg)",
+                                              boost::lexical_cast<std::string>(RadiansToDegrees(theta)));
 
-            TrackerSample_SetInfoDisplayMessage("p2cAngle (deg)",
-                                                boost::lexical_cast<std::string>(RadiansToDegrees(p2cAngle)));
+          TrackerSample_SetInfoDisplayMessage("p2cAngle (deg)",
+                                              boost::lexical_cast<std::string>(RadiansToDegrees(p2cAngle)));
 
-            TrackerSample_SetInfoDisplayMessage("ox (scene)",
-                                                boost::lexical_cast<std::string>(ox));
+          TrackerSample_SetInfoDisplayMessage("ox (scene)",
+                                              boost::lexical_cast<std::string>(ox));
 
-            TrackerSample_SetInfoDisplayMessage("offsetY (scene)",
-                                                boost::lexical_cast<std::string>(oy));
+          TrackerSample_SetInfoDisplayMessage("offsetY (scene)",
+                                              boost::lexical_cast<std::string>(oy));
 
-            TrackerSample_SetInfoDisplayMessage("pointX",
-                                                boost::lexical_cast<std::string>(pointX));
+          TrackerSample_SetInfoDisplayMessage("pointX",
+                                              boost::lexical_cast<std::string>(pointX));
 
-            TrackerSample_SetInfoDisplayMessage("pointY",
-                                                boost::lexical_cast<std::string>(pointY));
+          TrackerSample_SetInfoDisplayMessage("pointY",
+                                              boost::lexical_cast<std::string>(pointY));
 
-            TrackerSample_SetInfoDisplayMessage("angleDeg",
-                                                boost::lexical_cast<std::string>(angleDeg));
-          }
-#endif
+          TrackerSample_SetInfoDisplayMessage("angleDeg",
+                                              boost::lexical_cast<std::string>(angleDeg));
         }
+#endif
       }
-      else
-      {
-        RemoveFromScene();
-      }
-      lock->Invalidate();
     }
+    else
+    {
+      RemoveFromScene();
+    }
+
+    GetController().InvalidateViewport();
   }
 
 
--- a/OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.h	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.h	Fri Oct 09 16:33:43 2026 +0200
@@ -72,8 +72,7 @@
     };
 
   public:
-    static boost::shared_ptr<AngleMeasureTool> Create(boost::weak_ptr<IViewport> viewport,
-                                                      const boost::shared_ptr<ViewportController>& controller);
+    static boost::shared_ptr<AngleMeasureTool> Create(const boost::shared_ptr<ViewportController>& controller);
 
     ~AngleMeasureTool();
 
@@ -109,8 +108,7 @@
   private:
     class Tracker;
 
-    explicit AngleMeasureTool(boost::weak_ptr<IViewport> viewport,
-                              const boost::shared_ptr<ViewportController>& controller);
+    explicit AngleMeasureTool(const boost::shared_ptr<ViewportController>& controller);
 
     virtual void        RefreshScene() ORTHANC_OVERRIDE;
     void                RemoveFromScene();
--- a/OrthancStone/Sources/Scene2DViewport/LineMeasureTool.cpp	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/LineMeasureTool.cpp	Fri Oct 09 16:33:43 2026 +0200
@@ -47,7 +47,7 @@
   public:
     Tracker(const boost::shared_ptr<LineMeasureTool>& tool,
             bool isCreation,
-            const Scene2D& scene,
+            const Scene2D& scene,   // TODO Refactoring - The scene can be retrieved from the tool
             const PointerEvent& e) :
       tool_(tool),
       originalClickPosition_(e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform())),
@@ -145,9 +145,8 @@
   };
 
 
-  LineMeasureTool::LineMeasureTool(boost::weak_ptr<IViewport> viewport,
-                                   const boost::shared_ptr<ViewportController>& controller) :
-    MeasureTool(viewport, controller),
+  LineMeasureTool::LineMeasureTool(const boost::shared_ptr<ViewportController>& controller) :
+    MeasureTool(controller),
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
     layerHolder_(boost::shared_ptr<LayerHolder>(new LayerHolder(1, 5))),
 #else
@@ -159,10 +158,9 @@
 
   }
 
-  boost::shared_ptr<LineMeasureTool> LineMeasureTool::Create(boost::weak_ptr<IViewport> viewport,
-                                                             const boost::shared_ptr<ViewportController>& controller)
+  boost::shared_ptr<LineMeasureTool> LineMeasureTool::Create(const boost::shared_ptr<ViewportController>& controller)
   {
-    boost::shared_ptr<LineMeasureTool> obj(new LineMeasureTool(viewport, controller));
+    boost::shared_ptr<LineMeasureTool> obj(new LineMeasureTool(controller));
     obj->MeasureTool::PostConstructor();
     obj->RefreshScene();
     return obj;
@@ -178,12 +176,10 @@
 
   void LineMeasureTool::RemoveFromScene()
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-
-    if (layerHolder_->AreLayersCreated() && IsSceneAlive())
+    if (layerHolder_->AreLayersCreated())
     {
-      layerHolder_->DeleteLayers(lock->GetController().GetScene());
-      lock->Invalidate();
+      layerHolder_->DeleteLayers(GetController().GetScene());
+      GetController().InvalidateViewport();
     }
   }
   
@@ -273,10 +269,7 @@
   IFlexiblePointerTracker* LineMeasureTool::CreateEditionTracker(bool isCreation,
                                                                  const PointerEvent& e)
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-
-    ViewportController& controller = lock->GetController();
-    const Scene2D& scene = controller.GetScene();
+    const Scene2D& scene = GetController().GetScene();
     ScenePoint2D scenePos = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
 
     if (!HitTest(scene, scenePos))
@@ -304,103 +297,98 @@
 
   void LineMeasureTool::RefreshScene()
   {
-    if (IsSceneAlive())
+    if (IsEnabled())
     {
-      if (IsEnabled())
+      Scene2D& scene = GetController().GetScene();
+
+      layerHolder_->CreateLayersIfNeeded(scene);
+
       {
-        std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-        ViewportController& controller = lock->GetController();
-        Scene2D& scene = controller.GetScene();
+        // Fill the polyline layer with the measurement line
+
+        PolylineSceneLayer* polylineLayer = layerHolder_->GetPolylineLayer(scene, 0);
+        if (polylineLayer)
+        {
+          polylineLayer->ClearAllChains();
 
-        layerHolder_->CreateLayersIfNeeded(scene);
+          const Color color(TOOL_LINES_COLOR_RED, 
+                            TOOL_LINES_COLOR_GREEN, 
+                            TOOL_LINES_COLOR_BLUE);
 
-        {
-          // Fill the polyline layer with the measurement line
+          const Color highlightColor(TOOL_LINES_HL_COLOR_RED,
+                                     TOOL_LINES_HL_COLOR_GREEN,
+                                     TOOL_LINES_HL_COLOR_BLUE);
 
-          PolylineSceneLayer* polylineLayer = layerHolder_->GetPolylineLayer(scene, 0);
-          if (polylineLayer)
           {
-            polylineLayer->ClearAllChains();
+            PolylineSceneLayer::Chain chain;
+            chain.push_back(start_);
+            chain.push_back(end_);
+            if(lineHighlightArea_ == LineHighlightArea_Segment)
+              polylineLayer->AddChain(chain, false, highlightColor);
+            else
+              polylineLayer->AddChain(chain, false, color);
+          }
 
-            const Color color(TOOL_LINES_COLOR_RED, 
-                              TOOL_LINES_COLOR_GREEN, 
-                              TOOL_LINES_COLOR_BLUE);
-
-            const Color highlightColor(TOOL_LINES_HL_COLOR_RED,
-                                       TOOL_LINES_HL_COLOR_GREEN,
-                                       TOOL_LINES_HL_COLOR_BLUE);
+          // handles
+          {
+            {
+              PolylineSceneLayer::Chain chain;
+              
+              //TODO: take DPI into account
+              AddSquare(chain, scene, start_, GetHandleSideLengthS(scene));
+              
+              if (lineHighlightArea_ == LineHighlightArea_Start)
+                polylineLayer->AddChain(chain, true, highlightColor);
+              else
+                polylineLayer->AddChain(chain, true, color);
+            }
 
             {
               PolylineSceneLayer::Chain chain;
-              chain.push_back(start_);
-              chain.push_back(end_);
-              if(lineHighlightArea_ == LineHighlightArea_Segment)
-                polylineLayer->AddChain(chain, false, highlightColor);
-              else
-                polylineLayer->AddChain(chain, false, color);
-            }
-
-            // handles
-            {
-              {
-                PolylineSceneLayer::Chain chain;
               
-                //TODO: take DPI into account
-                AddSquare(chain, controller.GetScene(), start_, GetHandleSideLengthS(controller.GetScene()));
+              //TODO: take DPI into account
+              AddSquare(chain, scene, end_, GetHandleSideLengthS(scene));
               
-                if (lineHighlightArea_ == LineHighlightArea_Start)
-                  polylineLayer->AddChain(chain, true, highlightColor);
-                else
-                  polylineLayer->AddChain(chain, true, color);
-              }
-
-              {
-                PolylineSceneLayer::Chain chain;
-              
-                //TODO: take DPI into account
-                AddSquare(chain, controller.GetScene(), end_, GetHandleSideLengthS(controller.GetScene()));
-              
-                if (lineHighlightArea_ == LineHighlightArea_End)
-                  polylineLayer->AddChain(chain, true, highlightColor);
-                else
-                  polylineLayer->AddChain(chain, true, color);
-              }
+              if (lineHighlightArea_ == LineHighlightArea_End)
+                polylineLayer->AddChain(chain, true, highlightColor);
+              else
+                polylineLayer->AddChain(chain, true, color);
             }
           }
         }
+      }
+
+      {
+        // Set the text layer propreties
+        double deltaX = end_.GetX() - start_.GetX();
+        double deltaY = end_.GetY() - start_.GetY();
+        double squareDist = deltaX * deltaX + deltaY * deltaY;
+        double dist = sqrt(squareDist);
+        char buf[64];
+        sprintf(buf, "%0.02f mm", dist);
+
+        // TODO: for now we simply position the text overlay at the middle
+        // of the measuring segment
+        double midX = 0.5 * (end_.GetX() + start_.GetX());
+        double midY = 0.5 * (end_.GetY() + start_.GetY());
 
         {
-          // Set the text layer propreties
-          double deltaX = end_.GetX() - start_.GetX();
-          double deltaY = end_.GetY() - start_.GetY();
-          double squareDist = deltaX * deltaX + deltaY * deltaY;
-          double dist = sqrt(squareDist);
-          char buf[64];
-          sprintf(buf, "%0.02f mm", dist);
-
-          // TODO: for now we simply position the text overlay at the middle
-          // of the measuring segment
-          double midX = 0.5 * (end_.GetX() + start_.GetX());
-          double midY = 0.5 * (end_.GetY() + start_.GetY());
-
-          {
 
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
-            SetTextLayerOutlineProperties(
-              scene, layerHolder_, buf, ScenePoint2D(midX, midY), 0);
+          SetTextLayerOutlineProperties(
+            scene, layerHolder_, buf, ScenePoint2D(midX, midY), 0);
 #else
-            SetTextLayerProperties(
-              scene, layerHolder_, buf, ScenePoint2D(midX, midY), 0);
+          SetTextLayerProperties(
+            scene, layerHolder_, buf, ScenePoint2D(midX, midY), 0);
 #endif
-            lock->Invalidate();
-          }
         }
-        lock->Invalidate();
       }
-      else
-      {
-        RemoveFromScene();
-      }
+
+      GetController().InvalidateViewport();
+    }
+    else
+    {
+      RemoveFromScene();
     }
   }
 }
--- a/OrthancStone/Sources/Scene2DViewport/LineMeasureTool.h	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/LineMeasureTool.h	Fri Oct 09 16:33:43 2026 +0200
@@ -67,8 +67,7 @@
     };
 
   public:
-    static boost::shared_ptr<LineMeasureTool> Create(boost::weak_ptr<IViewport> viewport,
-                                                     const boost::shared_ptr<ViewportController>& controller);
+    static boost::shared_ptr<LineMeasureTool> Create(const boost::shared_ptr<ViewportController>& controller);
 
     ~LineMeasureTool();
 
@@ -103,8 +102,7 @@
   private:
     class Tracker;
 
-    explicit LineMeasureTool(boost::weak_ptr<IViewport> viewport,
-                             const boost::shared_ptr<ViewportController>& controller);
+    explicit LineMeasureTool(const boost::shared_ptr<ViewportController>& controller);
 
     virtual void        RefreshScene() ORTHANC_OVERRIDE;
     void                RemoveFromScene();
--- a/OrthancStone/Sources/Scene2DViewport/MeasureTool.cpp	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/MeasureTool.cpp	Fri Oct 09 16:33:43 2026 +0200
@@ -54,34 +54,14 @@
     return enabled_;
   }
 
-  IViewport::ILock* MeasureTool::GetViewportLock()
-  {
-    boost::shared_ptr<IViewport> viewport = viewport_.lock();
-    if (viewport)
-      return viewport->Lock();
-    else
-      return NULL;
-  }
-
-  IViewport::ILock* MeasureTool::GetViewportLock() const
-  {
-    boost::shared_ptr<IViewport> viewport = viewport_.lock();
-    if (viewport)
-      return viewport->Lock();
-    else
-      return NULL;
-  }
-
   double MeasureTool::GetHandleSideLengthS(const Scene2D& scene)
   {
     return HANDLE_SIDE_LENGTH_CANVAS_COORD * scene.GetCanvasToSceneTransform().ComputeZoom();
   }
 
-  MeasureTool::MeasureTool(boost::weak_ptr<IViewport> viewport,
-                           const boost::shared_ptr<ViewportController>& controller) :
+  MeasureTool::MeasureTool(const boost::shared_ptr<ViewportController>& controller) :
     enabled_(true),
-    controller_(controller),
-    viewport_(viewport)
+    controller_(controller)
   {
     if (!controller)
     {
@@ -94,16 +74,6 @@
     Register<ViewportController::SceneTransformChanged>(*controller_, &MeasureTool::OnSceneTransformChanged);
   }
 
-  bool MeasureTool::IsSceneAlive() const
-  {
-    // since the lifetimes of the viewport, viewportcontroller (and the
-    // measuring tools inside it) are linked, the scene is alive as 
-    // long as the viewport is alive (which is technically not the case
-    // during its dtor)
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-    return (lock != NULL);
-  }
-
   void MeasureTool::OnSceneTransformChanged(const ViewportController::SceneTransformChanged& message)
   {
     // TODO Refactoring - This is not called
--- a/OrthancStone/Sources/Scene2DViewport/MeasureTool.h	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/MeasureTool.h	Fri Oct 09 16:33:43 2026 +0200
@@ -51,19 +51,11 @@
 
 
   protected:
-    explicit MeasureTool(boost::weak_ptr<IViewport> viewport,  // TODO Refactoring - Remove
-                         const boost::shared_ptr<ViewportController>& controller);
+    explicit MeasureTool(const boost::shared_ptr<ViewportController>& controller);
 
     void PostConstructor();
 
     /**
-       The measuring tool may exist in a standalone fashion, without any available
-       scene (because the controller is dead or dying). This call allows to check 
-       before accessing the scene.
-    */
-    bool IsSceneAlive() const;
-
-    /**
        This is the meat of the tool: this method must [create (if needed) and]
        update the layers and their data according to the measure tool kind and
        current state. This is repeatedly called during user interaction
@@ -76,19 +68,6 @@
     */
     bool IsEnabled() const;
 
-    /**
-       Protected to allow sub-classes to use this weak pointer in factory methods
-       (pass them to created objects)
-    */
-    boost::weak_ptr<IViewport> viewport_;   // TODO Refactoring - Remove
-
-    /**
-    This will return a scoped lock to the viewport. 
-    If the viewport does not exist anymore, then nullptr is returned.
-    */
-    IViewport::ILock* GetViewportLock();
-    IViewport::ILock* GetViewportLock() const;
-
     static double GetHandleSideLengthS(const Scene2D& scene);
 
   public:
@@ -113,8 +92,7 @@
        This method is called when the scene transform changes. It allows to 
        recompute the visual elements whose content depend upon the scene transform
     */
-    void OnSceneTransformChanged(
-      const ViewportController::SceneTransformChanged& message);
+    void OnSceneTransformChanged(const ViewportController::SceneTransformChanged& message);
     
     /**
        This function must be implemented by the measuring tool to return whether
--- a/OrthancStone/Sources/Scene2DViewport/ViewportController.cpp	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/ViewportController.cpp	Fri Oct 09 16:33:43 2026 +0200
@@ -165,7 +165,7 @@
   {
     const ScenePoint2D p = event.GetMainPosition().Apply(scene_->GetCanvasToSceneTransform());
 
-    boost::shared_ptr<LineMeasureTool> tool = LineMeasureTool::Create(viewport_, shared_from_this());
+    boost::shared_ptr<LineMeasureTool> tool = LineMeasureTool::Create(shared_from_this());
     tool->Enable();
     tool->Set(p, p);
 
@@ -179,7 +179,7 @@
   {
     const ScenePoint2D p = event.GetMainPosition().Apply(scene_->GetCanvasToSceneTransform());
 
-    boost::shared_ptr<AngleMeasureTool> tool = AngleMeasureTool::Create(viewport_, shared_from_this());
+    boost::shared_ptr<AngleMeasureTool> tool = AngleMeasureTool::Create(shared_from_this());
     tool->Enable();
     tool->SetCenter(p);
     tool->SetSide1End(p);
--- a/OrthancStone/Sources/Scene2DViewport/ViewportController.h	Fri Oct 09 16:12:21 2026 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/ViewportController.h	Fri Oct 09 16:33:43 2026 +0200
@@ -191,6 +191,8 @@
       return activeTracker_.get() != NULL;
     }
 
+    void InvalidateViewport();
+
   private:
     // The scene can be used by the higher-level objects (including the
     // measuring tools), possibly in their destructor, and so it must be 
@@ -201,7 +203,5 @@
     boost::shared_ptr<UndoStack>                  undoStackW_;  // Global stack, possibly shared by all viewports
     std::vector<boost::shared_ptr<MeasureTool> >  measureTools_;  // TODO Refactoring - Make this a std::set?
     boost::shared_ptr<IFlexiblePointerTracker>    activeTracker_;  // TODO Refactoring - Couldn't this be a "std::unique_ptr"?
-
-    void InvalidateViewport();
   };
 }