changeset 722:28b9e3a54200

Undo mechanism implemented (not connected to UI yet). Undo stack and measuring tools are now handled by the ViewportController. Multi-touch does not crash trackers anymore.
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 21 May 2019 10:27:54 +0200
parents af0aa0c149fa
children 562cdd083b9e
files Framework/Scene2DViewport/AngleMeasureTool.cpp Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp Framework/Scene2DViewport/CreateAngleMeasureTracker.h Framework/Scene2DViewport/CreateLineMeasureTracker.cpp Framework/Scene2DViewport/CreateLineMeasureTracker.h Framework/Scene2DViewport/IFlexiblePointerTracker.h Framework/Scene2DViewport/LineMeasureTool.cpp Framework/Scene2DViewport/MeasureCommands.cpp Framework/Scene2DViewport/MeasureCommands.h Framework/Scene2DViewport/MeasureTools.cpp Framework/Scene2DViewport/MeasureTools.h Framework/Scene2DViewport/MeasureTrackers.cpp Framework/Scene2DViewport/MeasureTrackers.h Framework/Scene2DViewport/OneGesturePointerTracker.cpp Framework/Scene2DViewport/OneGesturePointerTracker.h Framework/Scene2DViewport/PointerTypes.h Framework/Scene2DViewport/ViewportController.cpp Framework/Scene2DViewport/ViewportController.h Framework/StoneException.h Platforms/Wasm/wasm-application-runner.ts Samples/Sdl/TrackerSampleApp.cpp Samples/Sdl/TrackerSampleApp.h
diffstat 22 files changed, 447 insertions(+), 303 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Scene2DViewport/AngleMeasureTool.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp	Tue May 21 10:27:54 2019 +0200
@@ -77,207 +77,209 @@
 
   void AngleMeasureTool::RefreshScene()
   {
-    if (IsEnabled())
+    if (IsSceneAlive())
     {
-      // get the scaling factor 
-      const double pixelToScene =
-        GetScene()->GetCanvasToSceneTransform().ComputeZoom();
 
-      if (!layersCreated)
+      if (IsEnabled())
       {
-        // Create the layers if need be
+        // get the scaling factor 
+        const double pixelToScene =
+          GetScene()->GetCanvasToSceneTransform().ComputeZoom();
 
-        assert(textBaseZIndex_ == -1);
+        if (!layersCreated)
         {
-          polylineZIndex_ = GetScene()->GetMaxDepth() + 100;
-          //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
-          std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
-          GetScene()->SetLayer(polylineZIndex_, layer.release());
+          // Create the layers if need be
 
-        }
-        {
-          textBaseZIndex_ = GetScene()->GetMaxDepth() + 100;
-          // create the four text background layers
+          assert(textBaseZIndex_ == -1);
           {
-            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-            GetScene()->SetLayer(textBaseZIndex_, layer.release());
-          }
-          {
-            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-            GetScene()->SetLayer(textBaseZIndex_+1, layer.release());
-          }
-          {
-            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-            GetScene()->SetLayer(textBaseZIndex_+2, layer.release());
+            polylineZIndex_ = GetScene()->GetMaxDepth() + 100;
+            //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
+            std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
+            GetScene()->SetLayer(polylineZIndex_, layer.release());
+
           }
           {
-            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-            GetScene()->SetLayer(textBaseZIndex_+3, layer.release());
+            textBaseZIndex_ = GetScene()->GetMaxDepth() + 100;
+            // create the four text background layers
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_, layer.release());
+            }
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 1, layer.release());
+            }
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 2, layer.release());
+            }
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 3, layer.release());
+            }
+
+            // and the text layer itself
+            {
+              std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+              GetScene()->SetLayer(textBaseZIndex_ + 4, layer.release());
+            }
+
           }
-          
-          // and the text layer itself
-          {
-            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-            GetScene()->SetLayer(textBaseZIndex_+4, layer.release());
-          }
-          
+          layersCreated = true;
+        }
+        else
+        {
+          assert(GetScene()->HasLayer(polylineZIndex_));
+          assert(GetScene()->HasLayer(textBaseZIndex_));
         }
-        layersCreated = true;
-      }
-      else
-      {
-        assert(GetScene()->HasLayer(polylineZIndex_));
-        assert(GetScene()->HasLayer(textBaseZIndex_));
-      }
-      {
-        // Fill the polyline layer with the measurement line
+        {
+          // Fill the polyline layer with the measurement line
+
+          PolylineSceneLayer* polylineLayer = GetPolylineLayer();
+          polylineLayer->ClearAllChains();
+          polylineLayer->SetColor(0, 183, 17);
 
-        PolylineSceneLayer* polylineLayer = GetPolylineLayer();
-        polylineLayer->ClearAllChains();
-        polylineLayer->SetColor(0, 183, 17);
+          // sides
+          {
+            {
+              PolylineSceneLayer::Chain chain;
+              chain.push_back(side1End_);
+              chain.push_back(center_);
+              polylineLayer->AddChain(chain, false);
+            }
+            {
+              PolylineSceneLayer::Chain chain;
+              chain.push_back(side2End_);
+              chain.push_back(center_);
+              polylineLayer->AddChain(chain, false);
+            }
+          }
 
-        // sides
-        {
+          // handles
+          {
+            //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), side1End_, 10.0 * pixelToScene); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), side2End_, 10.0 * pixelToScene); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+          }
+
+          // arc
           {
             PolylineSceneLayer::Chain chain;
-            chain.push_back(side1End_);
-            chain.push_back(center_);
-            polylineLayer->AddChain(chain, false);
-          }
-          {
-            PolylineSceneLayer::Chain chain;
-            chain.push_back(side2End_);
-            chain.push_back(center_);
+
+            const double ARC_RADIUS_CANVAS_COORD = 30.0;
+            AddShortestArc(chain, *GetScene(), side1End_, center_, side2End_,
+              ARC_RADIUS_CANVAS_COORD * pixelToScene);
             polylineLayer->AddChain(chain, false);
           }
         }
-
-        // handles
         {
-          //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
-
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, *GetScene(), side1End_, 10.0* pixelToScene); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
+          // Set the text layer
 
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, *GetScene(), side2End_, 10.0* pixelToScene); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
-        }
-
-        // arc
-        {
-          PolylineSceneLayer::Chain chain;
-
-          const double ARC_RADIUS_CANVAS_COORD = 30.0;
-          AddShortestArc(chain, *GetScene(), side1End_, center_, side2End_, 
-            ARC_RADIUS_CANVAS_COORD*pixelToScene);
-          polylineLayer->AddChain(chain, false);
-        }
-      }
-      {
-        // 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 delta = NormalizeAngle(p2cAngle - p1cAngle);
 
 
-        double theta = p1cAngle + delta/2;
+          double theta = p1cAngle + delta / 2;
 
 
-        const double TEXT_CENTER_DISTANCE_CANVAS_COORD = 90;
+          const double TEXT_CENTER_DISTANCE_CANVAS_COORD = 90;
 
-        double offsetX = TEXT_CENTER_DISTANCE_CANVAS_COORD * cos(theta);
+          double offsetX = TEXT_CENTER_DISTANCE_CANVAS_COORD * cos(theta);
 
-        double offsetY = TEXT_CENTER_DISTANCE_CANVAS_COORD * sin(theta);
+          double offsetY = TEXT_CENTER_DISTANCE_CANVAS_COORD * sin(theta);
 
-        double pointX = center_.GetX() + offsetX * pixelToScene;
-        double pointY = center_.GetY() + offsetY * pixelToScene;
+          double pointX = center_.GetX() + offsetX * pixelToScene;
+          double pointY = center_.GetY() + offsetY * pixelToScene;
 
-        char buf[64];
-        double angleDeg = RadiansToDegrees(delta);
+          char buf[64];
+          double angleDeg = 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);
 
-        SetTextLayerOutlineProperties(
-          *GetScene(), textBaseZIndex_, buf, ScenePoint2D(pointX, pointY));
+          SetTextLayerOutlineProperties(
+            *GetScene(), textBaseZIndex_, buf, ScenePoint2D(pointX, pointY));
 
-        // TODO:make it togglable
-        bool enableInfoDisplay = false;
-        if (enableInfoDisplay)
-        {
-          TrackerSample_SetInfoDisplayMessage("center_.GetX()",
-            boost::lexical_cast<std::string>(center_.GetX()));
+          // TODO:make it togglable
+          bool enableInfoDisplay = false;
+          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("offsetX (pix)",
-            boost::lexical_cast<std::string>(offsetX));
+            TrackerSample_SetInfoDisplayMessage("offsetX (pix)",
+              boost::lexical_cast<std::string>(offsetX));
 
-          TrackerSample_SetInfoDisplayMessage("offsetY (pix)",
-            boost::lexical_cast<std::string>(offsetY));
+            TrackerSample_SetInfoDisplayMessage("offsetY (pix)",
+              boost::lexical_cast<std::string>(offsetY));
 
-          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));
-        }
+            TrackerSample_SetInfoDisplayMessage("angleDeg",
+              boost::lexical_cast<std::string>(angleDeg));
+          }
 
 
 
+        }
       }
-    }
-    else
-    {
-      if (layersCreated)
+      else
       {
-        RemoveFromScene();
-        layersCreated = false;
+        if (layersCreated)
+        {
+          RemoveFromScene();
+          layersCreated = false;
+        }
       }
     }
   }
-
-
 }
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Tue May 21 10:27:54 2019 +0200
@@ -28,17 +28,14 @@
   CreateAngleMeasureTracker::CreateAngleMeasureTracker(
     MessageBroker&                  broker,
     ViewportControllerWPtr          controllerW,
-    std::vector<TrackerCommandPtr>& undoStack,
-    MeasureToolList&                measureTools,
     const PointerEvent&             e)
-    : CreateMeasureTracker(controllerW, undoStack, measureTools)
+    : CreateMeasureTracker(controllerW)
     , state_(CreatingSide1)
   {
     command_.reset(
       new CreateAngleMeasureCommand(
         broker,
         controllerW,
-        measureTools,
         e.GetMainPosition().Apply(GetScene()->GetCanvasToSceneTransform())));
   }
 
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Tue May 21 10:27:54 2019 +0200
@@ -40,8 +40,6 @@
     CreateAngleMeasureTracker(
       MessageBroker&                  broker,
       ViewportControllerWPtr          controllerW,
-      std::vector<TrackerCommandPtr>& undoStack,
-      MeasureToolList&                measureTools,
       const PointerEvent&             e);
 
     ~CreateAngleMeasureTracker();
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Tue May 21 10:27:54 2019 +0200
@@ -28,16 +28,13 @@
   CreateLineMeasureTracker::CreateLineMeasureTracker(
     MessageBroker&                  broker,
     ViewportControllerWPtr          controllerW,
-    std::vector<TrackerCommandPtr>& undoStack,
-    MeasureToolList&                measureTools,
     const PointerEvent&             e)
-    : CreateMeasureTracker(controllerW, undoStack, measureTools)
+    : CreateMeasureTracker(controllerW)
   {
     command_.reset(
       new CreateLineMeasureCommand(
         broker,
         controllerW,
-        measureTools,
         e.GetMainPosition().Apply(GetScene()->GetCanvasToSceneTransform())));
   }
 
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Tue May 21 10:27:54 2019 +0200
@@ -37,8 +37,6 @@
     CreateLineMeasureTracker(
       MessageBroker&                  broker,
       ViewportControllerWPtr          controllerW,
-      std::vector<TrackerCommandPtr>& undoStack,
-      MeasureToolList&                measureTools,
       const PointerEvent&             e);
 
     ~CreateLineMeasureTracker();
--- a/Framework/Scene2DViewport/IFlexiblePointerTracker.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/IFlexiblePointerTracker.h	Tue May 21 10:27:54 2019 +0200
@@ -53,6 +53,12 @@
     /**
     This method will be called when a touch/pointer is added (mouse down, 
     pen or finger press)
+
+    Important note: the initial pointer down that leads to creating the 
+    tracker is NOT sent to the tracker.
+
+    Thus, if you count the PointerDown vs PointerUp, there will be an extra
+    PointerUp.
     */
     virtual void PointerDown(const PointerEvent& event) = 0;
 
--- a/Framework/Scene2DViewport/LineMeasureTool.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/LineMeasureTool.cpp	Tue May 21 10:27:54 2019 +0200
@@ -85,116 +85,117 @@
 
   void LineMeasureTool::RefreshScene()
   {
-    if (IsEnabled())
+    if (IsSceneAlive())
     {
-      if (!layersCreated)
+      if (IsEnabled())
       {
-        // Create the layers if need be
+        if (!layersCreated)
+        {
+          // Create the layers if need be
 
-        assert(textZIndex_ == -1);
+          assert(textZIndex_ == -1);
+          {
+            polylineZIndex_ = GetScene()->GetMaxDepth() + 100;
+            //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
+            std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
+            GetScene()->SetLayer(polylineZIndex_, layer.release());
+          }
+          {
+            textZIndex_ = GetScene()->GetMaxDepth() + 100;
+            //LOG(INFO) << "set textZIndex_ to: " << textZIndex_;
+            std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+            GetScene()->SetLayer(textZIndex_, layer.release());
+          }
+          layersCreated = true;
+        }
+        else
         {
-          polylineZIndex_ = GetScene()->GetMaxDepth() + 100;
-          //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_;
-          std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
-          GetScene()->SetLayer(polylineZIndex_, layer.release());
+          assert(GetScene()->HasLayer(polylineZIndex_));
+          assert(GetScene()->HasLayer(textZIndex_));
         }
         {
-          textZIndex_ = GetScene()->GetMaxDepth() + 100;
-          //LOG(INFO) << "set textZIndex_ to: " << textZIndex_;
-          std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-          GetScene()->SetLayer(textZIndex_, layer.release());
-        }
-        layersCreated = true;
-      }
-      else
-      {
-        assert(GetScene()->HasLayer(polylineZIndex_));
-        assert(GetScene()->HasLayer(textZIndex_));
-      }
-      {
-        // Fill the polyline layer with the measurement line
+          // Fill the polyline layer with the measurement line
 
-        PolylineSceneLayer* polylineLayer = GetPolylineLayer();
-        polylineLayer->ClearAllChains();
-        polylineLayer->SetColor(0, 223, 21);
-
-        {
-          PolylineSceneLayer::Chain chain;
-          chain.push_back(start_);
-          chain.push_back(end_);
-          polylineLayer->AddChain(chain, false);
-        }
-
-        // handles
-        {
-          //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
-
-          {
-            PolylineSceneLayer::Chain chain;
-            AddSquare(chain, *GetScene(), start_, 10.0); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
-          }
+          PolylineSceneLayer* polylineLayer = GetPolylineLayer();
+          polylineLayer->ClearAllChains();
+          polylineLayer->SetColor(0, 223, 21);
 
           {
             PolylineSceneLayer::Chain chain;
-            AddSquare(chain, *GetScene(), end_, 10.0); //TODO: take DPI into account
-            polylineLayer->AddChain(chain, true);
+            chain.push_back(start_);
+            chain.push_back(end_);
+            polylineLayer->AddChain(chain, false);
           }
 
-          //ScenePoint2D startC = start_.Apply(GetScene()->GetSceneToCanvasTransform());
-          //double squareSize = 10.0; 
-          //double startHandleLX = startC.GetX() - squareSize/2;
-          //double startHandleTY = startC.GetY() - squareSize / 2;
-          //double startHandleRX = startC.GetX() + squareSize / 2;
-          //double startHandleBY = startC.GetY() + squareSize / 2;
-          //ScenePoint2D startLTC(startHandleLX, startHandleTY);
-          //ScenePoint2D startRTC(startHandleRX, startHandleTY);
-          //ScenePoint2D startRBC(startHandleRX, startHandleBY);
-          //ScenePoint2D startLBC(startHandleLX, startHandleBY);
+          // handles
+          {
+            //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength)
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), start_, 10.0); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+
+            {
+              PolylineSceneLayer::Chain chain;
+              AddSquare(chain, *GetScene(), end_, 10.0); //TODO: take DPI into account
+              polylineLayer->AddChain(chain, true);
+            }
+
+            //ScenePoint2D startC = start_.Apply(GetScene()->GetSceneToCanvasTransform());
+            //double squareSize = 10.0; 
+            //double startHandleLX = startC.GetX() - squareSize/2;
+            //double startHandleTY = startC.GetY() - squareSize / 2;
+            //double startHandleRX = startC.GetX() + squareSize / 2;
+            //double startHandleBY = startC.GetY() + squareSize / 2;
+            //ScenePoint2D startLTC(startHandleLX, startHandleTY);
+            //ScenePoint2D startRTC(startHandleRX, startHandleTY);
+            //ScenePoint2D startRBC(startHandleRX, startHandleBY);
+            //ScenePoint2D startLBC(startHandleLX, startHandleBY);
 
-          //ScenePoint2D startLT = startLTC.Apply(GetScene()->GetCanvasToSceneTransform());
-          //ScenePoint2D startRT = startRTC.Apply(GetScene()->GetCanvasToSceneTransform());
-          //ScenePoint2D startRB = startRBC.Apply(GetScene()->GetCanvasToSceneTransform());
-          //ScenePoint2D startLB = startLBC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startLT = startLTC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startRT = startRTC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startRB = startRBC.Apply(GetScene()->GetCanvasToSceneTransform());
+            //ScenePoint2D startLB = startLBC.Apply(GetScene()->GetCanvasToSceneTransform());
+
+            //PolylineSceneLayer::Chain chain;
+            //chain.push_back(startLT);
+            //chain.push_back(startRT);
+            //chain.push_back(startRB);
+            //chain.push_back(startLB);
+            //polylineLayer->AddChain(chain, true);
+          }
+
+        }
+        {
+          // Set the text layer proporeties
 
-          //PolylineSceneLayer::Chain chain;
-          //chain.push_back(startLT);
-          //chain.push_back(startRT);
-          //chain.push_back(startRB);
-          //chain.push_back(startLB);
-          //polylineLayer->AddChain(chain, true);
+          TextSceneLayer* textLayer = GetTextLayer();
+          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 units", dist);
+          textLayer->SetText(buf);
+          textLayer->SetColor(0, 223, 21);
+
+          // 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());
+          textLayer->SetPosition(midX, midY);
         }
-
       }
+      else
       {
-        // Set the text layer proporeties
-
-        TextSceneLayer* textLayer = GetTextLayer();
-        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 units", dist);
-        textLayer->SetText(buf);
-        textLayer->SetColor(0, 223, 21);
-
-        // 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());
-        textLayer->SetPosition(midX, midY);
-      }
-    }
-    else
-    {
-      if (layersCreated)
-      {
-        RemoveFromScene();
-        layersCreated = false;
+        if (layersCreated)
+        {
+          RemoveFromScene();
+          layersCreated = false;
+        }
       }
     }
   }
-
-
 }
\ No newline at end of file
--- a/Framework/Scene2DViewport/MeasureCommands.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureCommands.cpp	Tue May 21 10:27:54 2019 +0200
@@ -20,23 +20,24 @@
 
 #include "MeasureCommands.h"
 
+#include <boost/make_shared.hpp>
+#include <boost/ref.hpp>
+
 namespace OrthancStone
 {
   void CreateMeasureCommand::Undo()
   {
     // simply disable the measure tool upon undo
-    GetMeasureTool()->Disable();
+    GetController()->RemoveMeasureTool(GetMeasureTool());
   }
 
   void CreateMeasureCommand::Redo()
   {
-    GetMeasureTool()->Enable();
+    GetController()->AddMeasureTool(GetMeasureTool());
   }
 
-  CreateMeasureCommand::CreateMeasureCommand(
-    ViewportControllerWPtr controllerW, MeasureToolList& measureTools)
+  CreateMeasureCommand::CreateMeasureCommand(ViewportControllerWPtr controllerW)
     : TrackerCommand(controllerW)
-    , measureTools_(measureTools)
   {
 
   }
@@ -50,12 +51,12 @@
   CreateLineMeasureCommand::CreateLineMeasureCommand(
     MessageBroker&         broker, 
     ViewportControllerWPtr controllerW,
-    MeasureToolList&       measureTools, 
     ScenePoint2D           point)
-    : CreateMeasureCommand(controllerW, measureTools)
-    , measureTool_(new LineMeasureTool(broker, controllerW))
+    : CreateMeasureCommand(controllerW)
+    , measureTool_(
+        boost::make_shared<LineMeasureTool>(boost::ref(broker), controllerW))
   {
-    measureTools_.push_back(measureTool_);
+    GetController()->AddMeasureTool(measureTool_);
     measureTool_->Set(point, point);
   }
 
@@ -67,12 +68,12 @@
   CreateAngleMeasureCommand::CreateAngleMeasureCommand(
     MessageBroker&         broker, 
     ViewportControllerWPtr controllerW,
-    MeasureToolList&       measureTools, 
     ScenePoint2D           point)
-    : CreateMeasureCommand(controllerW, measureTools)
-    , measureTool_(new AngleMeasureTool(broker, controllerW))
+    : CreateMeasureCommand(controllerW)
+    , measureTool_(
+      boost::make_shared<AngleMeasureTool>(boost::ref(broker), controllerW))
   {
-    measureTools_.push_back(measureTool_);
+    GetController()->AddMeasureTool(measureTool_);
     measureTool_->SetSide1End(point);
     measureTool_->SetCenter(point);
     measureTool_->SetSide2End(point);
@@ -90,4 +91,10 @@
     measureTool_->SetSide2End(scenePos);
   }
 
+  ViewportControllerPtr TrackerCommand::GetController()
+  {
+    ViewportControllerPtr controller = controllerW_.lock();
+    assert(controller); // accessing dead object?
+    return controller;
+  }
 }
--- a/Framework/Scene2DViewport/MeasureCommands.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureCommands.h	Tue May 21 10:27:54 2019 +0200
@@ -43,19 +43,17 @@
     virtual void Redo() = 0;
 
   protected:
+    ViewportControllerPtr  GetController();
     ViewportControllerWPtr controllerW_;
   };
 
   class CreateMeasureCommand : public TrackerCommand
   {
   public:
-    CreateMeasureCommand(
-      ViewportControllerWPtr controllerW, MeasureToolList& measureTools);
+    CreateMeasureCommand(ViewportControllerWPtr controllerW);
     ~CreateMeasureCommand();
     virtual void Undo() ORTHANC_OVERRIDE;
     virtual void Redo() ORTHANC_OVERRIDE;
-  protected:
-    MeasureToolList& measureTools_;
   private:
     /** Must be implemented by the subclasses that create the actual tool */
     virtual MeasureToolPtr GetMeasureTool() = 0;
@@ -67,7 +65,6 @@
     CreateLineMeasureCommand(
       MessageBroker&         broker, 
       ViewportControllerWPtr controllerW,
-      MeasureToolList&       measureTools, 
       ScenePoint2D           point);
     
     // the starting position is set in the ctor
@@ -89,7 +86,6 @@
     CreateAngleMeasureCommand(
       MessageBroker&         broker, 
       ViewportControllerWPtr controllerW,
-      MeasureToolList&       measureTools, 
       ScenePoint2D           point);
 
     /** This method sets center*/
--- a/Framework/Scene2DViewport/MeasureTools.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureTools.cpp	Tue May 21 10:27:54 2019 +0200
@@ -79,6 +79,13 @@
       (*this, &MeasureTool::OnSceneTransformChanged));
   }
 
+
+  bool MeasureTool::IsSceneAlive() const
+  {
+    ViewportControllerPtr controller = controllerW_.lock();
+    return (controller.get() != NULL);
+  }
+
   void MeasureTool::OnSceneTransformChanged(
     const ViewportController::SceneTransformChanged& message)
   {
--- a/Framework/Scene2DViewport/MeasureTools.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureTools.h	Tue May 21 10:27:54 2019 +0200
@@ -63,6 +63,13 @@
 
   protected:
     MeasureTool(MessageBroker& broker, ViewportControllerWPtr controllerW);
+
+    /**
+    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]
--- a/Framework/Scene2DViewport/MeasureTrackers.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureTrackers.cpp	Tue May 21 10:27:54 2019 +0200
@@ -26,14 +26,9 @@
 namespace OrthancStone
 {
 
-  CreateMeasureTracker::CreateMeasureTracker(
-    ViewportControllerWPtr          controllerW,
-    std::vector<TrackerCommandPtr>& undoStack,
-    std::vector<MeasureToolPtr>&    measureTools)
+  CreateMeasureTracker::CreateMeasureTracker(ViewportControllerWPtr controllerW)
     : controllerW_(controllerW)
     , alive_(true)
-    , undoStack_(undoStack)
-    , measureTools_(measureTools)
     , commitResult_(true)
   {
   }
@@ -56,12 +51,11 @@
 
     // otherwise, we simply undo it
     if (commitResult_)
-      undoStack_.push_back(command_);
+      controllerW_.lock()->PushCommand(command_);
     else
       command_->Undo();
   }
 
-
   OrthancStone::Scene2DPtr CreateMeasureTracker::GetScene()
   {
     return controllerW_.lock()->GetScene();
--- a/Framework/Scene2DViewport/MeasureTrackers.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureTrackers.h	Tue May 21 10:27:54 2019 +0200
@@ -37,10 +37,7 @@
     virtual void Cancel() ORTHANC_OVERRIDE;
     virtual bool IsAlive() const ORTHANC_OVERRIDE;
   protected:
-    CreateMeasureTracker(
-      ViewportControllerWPtr          controllerW,
-      std::vector<TrackerCommandPtr>& undoStack,
-      std::vector<MeasureToolPtr>&    measureTools);
+    CreateMeasureTracker(ViewportControllerWPtr controllerW);
 
     ~CreateMeasureTracker();
   
@@ -51,8 +48,6 @@
     Scene2DPtr                      GetScene();
 
   private:
-    std::vector<TrackerCommandPtr>& undoStack_;
-    std::vector<MeasureToolPtr>&    measureTools_;
     bool                            commitResult_;
   };
 }
--- a/Framework/Scene2DViewport/OneGesturePointerTracker.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/OneGesturePointerTracker.cpp	Tue May 21 10:27:54 2019 +0200
@@ -23,6 +23,8 @@
 
 #include <Core/OrthancException.h>
 
+#include <Framework/StoneException.h>
+
 using namespace Orthanc;
 
 namespace OrthancStone
@@ -31,17 +33,30 @@
     ViewportControllerWPtr controllerW)
     : controllerW_(controllerW)
     , alive_(true)
+    , currentTouchCount_(1)
   {
   }
 
   void OneGesturePointerTracker::PointerUp(const PointerEvent& event)
   {
-    alive_ = false;
+    // pointer up is only called for the LAST up event in case of a multi-touch
+    // gesture
+    ORTHANC_ASSERT(currentTouchCount_ > 0, "Wrong state in tracker");
+    currentTouchCount_--;
+    LOG(INFO) << "currentTouchCount_ becomes: " << currentTouchCount_;
+    if (currentTouchCount_ == 0)
+    {
+      LOG(INFO) << "currentTouchCount_ == 0 --> alive_ = false";
+      alive_ = false;
+    }
   }
 
   void OneGesturePointerTracker::PointerDown(const PointerEvent& event)
   {
-    throw OrthancException(ErrorCode_InternalError, "Wrong state in tracker");
+    // additional touches are not taken into account but we need to count 
+    // the number of active touches
+    currentTouchCount_++;
+    LOG(INFO) << "currentTouchCount_ becomes: " << currentTouchCount_;
   }
 
   bool OneGesturePointerTracker::IsAlive() const
--- a/Framework/Scene2DViewport/OneGesturePointerTracker.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/OneGesturePointerTracker.h	Tue May 21 10:27:54 2019 +0200
@@ -26,14 +26,15 @@
 {
   /**
   This base is class allows to write simple trackers that deal with single 
-  drag gestures. It is *not* suitables for multi-state trackers where various
-  mouse operations need to be handled.
+  drag gestures with only one touch. It is *not* suitable for multi-touch and
+  multi-state trackers where various mouse operations need to be handled.
 
   In order to write such a tracker:
   - subclass this class
   - you may store the initial click/touch position in the constructor
   - implement PointerMove to react to pointer/touch events
   - implement Cancel to restore the state at initial tracker creation time
+
   */
   class OneGesturePointerTracker : public IFlexiblePointerTracker
   {
@@ -49,6 +50,7 @@
   private:
     ViewportControllerWPtr controllerW_;
     bool                   alive_;
+    int                    currentTouchCount_;
   };
 }
 
--- a/Framework/Scene2DViewport/PointerTypes.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/PointerTypes.h	Tue May 21 10:27:54 2019 +0200
@@ -37,8 +37,6 @@
     MeasureToolPtr;
   typedef boost::weak_ptr<MeasureTool>
     MeasureToolWPtr;
-  typedef std::vector<MeasureToolPtr>
-    MeasureToolList;
 
   class LineMeasureTool;
   typedef boost::shared_ptr<LineMeasureTool>
--- a/Framework/Scene2DViewport/ViewportController.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/ViewportController.cpp	Tue May 21 10:27:54 2019 +0200
@@ -19,6 +19,7 @@
  **/
 
 #include "ViewportController.h"
+#include "MeasureCommands.h"
 
 #include <Framework/StoneException.h>
 
@@ -30,6 +31,7 @@
 {
   ViewportController::ViewportController(MessageBroker& broker)
     : IObservable(broker)
+    , numAppliedCommands_(0)
   {
     scene_ = boost::make_shared<Scene2D>();
   }
@@ -81,5 +83,55 @@
     BroadcastMessage(SceneTransformChanged(*this));
   }
 
+  void ViewportController::PushCommand(TrackerCommandPtr command)
+  {
+    commandStack_.erase(
+      commandStack_.begin() + numAppliedCommands_,
+      commandStack_.end());
+    
+    ORTHANC_ASSERT(std::find(commandStack_.begin(), commandStack_.end(), command) 
+      == commandStack_.end(), "Duplicate command");
+    commandStack_.push_back(command);
+    numAppliedCommands_++;
+  }
+
+  void ViewportController::Undo()
+  {
+    ORTHANC_ASSERT(CanUndo(), "");
+    commandStack_[numAppliedCommands_-1]->Undo();
+    numAppliedCommands_--;
+  }
+
+  void ViewportController::Redo()
+  {
+    ORTHANC_ASSERT(CanRedo(), "");
+    commandStack_[numAppliedCommands_]->Redo();
+    numAppliedCommands_++;
+  }
+
+  bool ViewportController::CanUndo() const
+  {
+    return numAppliedCommands_ > 0;
+  }
+
+  bool ViewportController::CanRedo() const
+  {
+    return numAppliedCommands_ < commandStack_.size();
+  }
+
+  void ViewportController::AddMeasureTool(MeasureToolPtr measureTool)
+  {
+    ORTHANC_ASSERT(std::find(measureTools_.begin(), measureTools_.end(), measureTool)
+      == measureTools_.end(), "Duplicate measure tool");
+    measureTools_.push_back(measureTool);
+  }
+
+  void ViewportController::RemoveMeasureTool(MeasureToolPtr measureTool)
+  {
+    ORTHANC_ASSERT(std::find(measureTools_.begin(), measureTools_.end(), measureTool)
+      != measureTools_.end(), "Measure tool not found");
+    measureTools_.push_back(measureTool);
+  }
+
 }
 
--- a/Framework/Scene2DViewport/ViewportController.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/Scene2DViewport/ViewportController.h	Tue May 21 10:27:54 2019 +0200
@@ -26,6 +26,8 @@
 #include <Framework/Scene2D/PointerEvent.h>
 #include <Framework/Scene2DViewport/IFlexiblePointerTracker.h>
 
+#include <stack>
+
 namespace OrthancStone
 {
   /**
@@ -81,8 +83,54 @@
     /** Forwarded to the underlying scene, and broadcasted to the observers */
     void FitContent(unsigned int canvasWidth, unsigned int canvasHeight);
 
+    /** 
+    Stores a command : 
+    - this first trims the undo stack to keep the first numAppliedCommands_ 
+    - then it adds the supplied command at the top of the undo stack
+
+    In other words, when a new command is pushed, all the undone (and not 
+    redone) commands are removed.
+    */
+    void PushCommand(TrackerCommandPtr command);
+
+    /**
+    Undoes the command at the top of the undo stack, or throws if there is no
+    command to undo.
+    You can check "CanUndo" first to protect against extraneous redo.
+    */
+    void Undo();
+
+    /**
+    Redoes the command that is just above the last applied command in the undo
+    stack or throws if there is no command to redo. 
+    You can check "CanRedo" first to protect against extraneous redo.
+    */
+    void Redo();
+
+    /** selfexpl */
+    bool CanUndo() const;
+
+    /** selfexpl */
+    bool CanRedo() const;
+
+    /** Adds a new measure tool */
+    void AddMeasureTool(MeasureToolPtr measureTool);
+
+    /** Removes a measure tool or throws if it cannot be found */
+    void RemoveMeasureTool(MeasureToolPtr measureTool);
+
   private:
-    Scene2DPtr                scene_;
-    FlexiblePointerTrackerPtr tracker_;
+    std::vector<TrackerCommandPtr> commandStack_;
+    
+    /**
+    This is always between >= 0 and <= undoStack_.size() and gives the 
+    position where the controller is in the undo stack. 
+    - If numAppliedCommands_ > 0, one can undo
+    - If numAppliedCommands_ < numAppliedCommands_.size(), one can redo
+    */
+    size_t                         numAppliedCommands_;
+    std::vector<MeasureToolPtr>    measureTools_;
+    Scene2DPtr                     scene_;
+    FlexiblePointerTrackerPtr      tracker_;
   };
 }
--- a/Framework/StoneException.h	Mon May 20 12:49:29 2019 +0200
+++ b/Framework/StoneException.h	Tue May 21 10:27:54 2019 +0200
@@ -113,3 +113,13 @@
 
 }
 
+// See https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-multi-stmts
+// (or google "Multiple lines macro C++ faq lite" if link is dead)
+#define ORTHANC_ASSERT(cond,streamChainMessage) \
+    if (!(cond)) { \
+      std::stringstream sst; \
+      sst << "Assertion failed. Condition = \"" #cond "\" Message = \"" << streamChainMessage << "\""; \
+      std::string sstr = sst.str(); \
+      throw OrthancException(ErrorCode_InternalError,sstr.c_str()); \
+    } else (void)0
+
--- a/Platforms/Wasm/wasm-application-runner.ts	Mon May 20 12:49:29 2019 +0200
+++ b/Platforms/Wasm/wasm-application-runner.ts	Tue May 21 10:27:54 2019 +0200
@@ -22,6 +22,15 @@
 var StartWasmApplication: Function = null;
 export var SendSerializedMessageToStoneApplication: Function = null;
 
+var auxiliaryParameters : Map<string,string>  = null;
+
+export function SetApplicationParameters(params : Map<string,string>) {
+  if (auxiliaryParameters != null) {
+    console.warn("wasm-application-runner.SetApplicationParameters: about to overwrite the existing application parameters!")
+  }
+  auxiliaryParameters = params;
+}
+
 function DoAnimationThread() {
   if (WasmDoAnimation != null) {
     WasmDoAnimation();
@@ -31,6 +40,7 @@
   setTimeout(DoAnimationThread, 100);  
 }
 
+
 function GetUriParameters(): Map<string, string> {
   var parameters = window.location.search.substr(1);
 
@@ -63,7 +73,16 @@
 
   CreateWasmApplication();
 
-  // parse uri and transmit the parameters to the app before initializing it
+  // transmit the API-specified parameters to the app before initializing it
+  for (let key in auxiliaryParameters) {
+    if (auxiliaryParameters.hasOwnProperty(key)) {
+      Logger.defaultLogger.debug(
+        `About to call SetStartupParameter("${key}","${auxiliaryParameters[key]}")`);
+      SetStartupParameter(key, auxiliaryParameters[key]);
+    }
+  }
+
+  // parse uri and transmit the URI parameters to the app before initializing it
   let parameters = GetUriParameters();
 
   for (let key in parameters) {
--- a/Samples/Sdl/TrackerSampleApp.cpp	Mon May 20 12:49:29 2019 +0200
+++ b/Samples/Sdl/TrackerSampleApp.cpp	Tue May 21 10:27:54 2019 +0200
@@ -322,17 +322,17 @@
           return FlexiblePointerTrackerPtr(new ZoomSceneTracker(
             controller_, e, compositor_->GetCanvasHeight()));
         //case GuiTool_AngleMeasure:
-        //  return new AngleMeasureTracker(GetScene(), measureTools_, undoStack_, e);
+        //  return new AngleMeasureTracker(GetScene(), e);
         //case GuiTool_CircleMeasure:
-        //  return new CircleMeasureTracker(GetScene(), measureTools_, undoStack_, e);
+        //  return new CircleMeasureTracker(GetScene(), e);
         //case GuiTool_EllipseMeasure:
-        //  return new EllipseMeasureTracker(GetScene(), measureTools_, undoStack_, e);
+        //  return new EllipseMeasureTracker(GetScene(), e);
         case GuiTool_LineMeasure:
           return FlexiblePointerTrackerPtr(new CreateLineMeasureTracker(
-            IObserver::GetBroker(), controller_, undoStack_, measureTools_, e));
+            IObserver::GetBroker(), controller_, e));
         case GuiTool_AngleMeasure:
           return FlexiblePointerTrackerPtr(new CreateAngleMeasureTracker(
-            IObserver::GetBroker(), controller_, undoStack_, measureTools_, e));
+            IObserver::GetBroker(), controller_, e));
         case GuiTool_CircleMeasure:
           LOG(ERROR) << "Not implemented yet!";
           return FlexiblePointerTrackerPtr();
--- a/Samples/Sdl/TrackerSampleApp.h	Mon May 20 12:49:29 2019 +0200
+++ b/Samples/Sdl/TrackerSampleApp.h	Tue May 21 10:27:54 2019 +0200
@@ -114,14 +114,9 @@
 
     std::map<std::string, std::string> infoTextMap_;
     FlexiblePointerTrackerPtr activeTracker_;
-    std::vector<TrackerCommandPtr> undoStack_;
-
-    // we store the measure tools here so that they don't get deleted
-    std::vector<MeasureToolPtr> measureTools_;
 
     //static const int LAYER_POSITION = 150;
 
-
     int TEXTURE_2x2_1_ZINDEX;
     int TEXTURE_1x1_ZINDEX;
     int TEXTURE_2x2_2_ZINDEX;