From 982e04286e84b06bf08519d080f5333018ed0280 Mon Sep 17 00:00:00 2001
From: gferret <gatien.ferret@kitware.com>
Date: Mon, 22 Aug 2022 14:55:10 +0200
Subject: [PATCH] [feat] Add in the UI of the ensor list tool to live transform
 data

Add sliders for translations and rotation updates, linked to lidar proxies to help manipulate the sensor data
---
 .../lqLoadLidarStateReaction.cxx              |  75 +--
 .../lqLoadLidarStateReaction.h                |  13 -
 .../SensorWidget/lqSensorReaderWidget.cxx     |   5 +-
 .../SensorWidget/lqSensorReaderWidget.h       |   5 +
 .../SensorWidget/lqSensorWidget.cxx           | 362 ++++++++++++++
 .../SensorWidget/lqSensorWidget.h             |  72 +++
 .../SensorWidget/lqSensorWidget.ui            | 461 +++++++++++++++++-
 ApplicationComponents/lqHelper.cxx            |  69 +++
 ApplicationComponents/lqHelper.h              |  13 +
 9 files changed, 975 insertions(+), 100 deletions(-)

diff --git a/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.cxx b/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.cxx
index 50752f3b8..6e6b9c3a7 100644
--- a/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.cxx
+++ b/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.cxx
@@ -110,8 +110,8 @@ void lqLoadLidarStateReaction::LoadLidarState(vtkSMProxy * lidarCurrentProxy)
           QMessageBox::information(nullptr, tr(""), tr(message.c_str()) );
         }
         else
-        {
-          lqLoadLidarStateReaction::UpdateProxyProperty(lidarProxy, propertyName, currentProp.values);
+        {        
+          UpdateProxyProperty(lidarProxy, propertyName, currentProp.values);
         }
       }
     }
@@ -162,74 +162,3 @@ void lqLoadLidarStateReaction::ParseJsonContent(Json::Value contents, std::strin
     }
   }
 }
-
-//-----------------------------------------------------------------------------
-int lqLoadLidarStateReaction::UpdateProxyProperty(vtkSMProxy * proxy, const std::string &propNameToFind,
-                        const std::vector<std::string> &values)
-{
-  // If there is no value to set, the request is skipped
-  if(values.empty())
-  {
-    std::string message = "Property " + propNameToFind + " couldn't be applied";
-    QMessageBox::information(nullptr, QObject::tr(""), QObject::tr(message.c_str()) );
-    return 0;
-  }
-
-  vtkSMProperty* prop = GetPropertyFromProxy(proxy, propNameToFind);
-
-  if(!prop)
-  {
-    return 0;
-  }
-
-  std::vector<double> propertyAsDoubleArray = vtkSMPropertyHelper(prop).GetDoubleArray();
-  if(propertyAsDoubleArray.size() > 1)
-  {
-    if(propertyAsDoubleArray.size() != values.size())
-    {
-      std::cout << "Values to applied and base property does not have the same size" << std::endl;
-    }
-    std::vector<double> d;
-    for(unsigned int j = 0; j < values.size(); j++)
-    {
-      d.push_back(std::stod(values[j]));
-    }
-    vtkSMPropertyHelper(prop).Set(d.data(), d.size());
-    proxy->UpdateProperty(propNameToFind.c_str());
-    return 1;
-  }
-  else
-  {
-    // If the property is a valid variant we display it to the user
-    vtkVariant propertyAsVariant = vtkSMPropertyHelper(prop).GetAsVariant(0);
-    if(propertyAsVariant.IsValid())
-    {
-      if(propertyAsVariant.IsInt())
-      {
-        vtkSMBooleanDomain * boolDomain = vtkSMBooleanDomain::SafeDownCast(prop->FindDomain("vtkSMBooleanDomain"));
-        if(boolDomain && (values[0].compare("false") == 0 || values[0].compare("true") == 0))
-        {
-          int value = (values[0].compare("false") == 0) ? 0 : 1;
-          vtkSMPropertyHelper(prop).Set(value);
-        }
-        else
-        {
-          vtkSMPropertyHelper(prop).Set(std::stoi(values[0]));
-        }
-      }
-      else if(propertyAsVariant.IsNumeric())
-      {
-        vtkSMPropertyHelper(prop).Set(std::stof(values[0]));
-
-      }
-      else if(propertyAsVariant.IsString())
-      {
-        vtkSMPropertyHelper(prop).Set(values[0].c_str());
-      }
-      proxy->UpdateProperty(propNameToFind.c_str());
-      return 1;
-    }
-  }
-  return 0;
-}
-
diff --git a/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.h b/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.h
index ba5bc7299..03afbca23 100644
--- a/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.h
+++ b/ApplicationComponents/SaveAndLoadLidarState/lqLoadLidarStateReaction.h
@@ -27,19 +27,6 @@ public:
 
   static void LoadLidarState(vtkSMProxy * lidarCurrentProxy);
 
-  /**
-   * @brief UpdateProxyProperty set the values to the property "propNameToFind" of the proxy
-   *        If the property is not found in the proxy, a message is displayed but nothing is done.
-   *        This function is useful, if the property type is unknown.
-   *        If it is known, you should directly use vtkSMPropertyHelper to set the property
-   * @param proxy proxy where to search the property
-   * @param propNameToFind name of the property
-   * @param values properties values to set
-   * @return 1 if the property has been well set, 0 otherwise
-   */
-  static int UpdateProxyProperty(vtkSMProxy * proxy, const std::string & propNameToFind,
-                                 const std::vector<std::string> & values);
-
 public slots:
   /**
   * Called when the action is triggered.
diff --git a/ApplicationComponents/SensorWidget/lqSensorReaderWidget.cxx b/ApplicationComponents/SensorWidget/lqSensorReaderWidget.cxx
index 960609d7c..0ce8dc8a2 100644
--- a/ApplicationComponents/SensorWidget/lqSensorReaderWidget.cxx
+++ b/ApplicationComponents/SensorWidget/lqSensorReaderWidget.cxx
@@ -7,6 +7,9 @@
 #include <vtkSMPropertyHelper.h>
 #include <vtkSMProxy.h>
 
+#include <iostream>
+#include <fstream>
+
 //-----------------------------------------------------------------------------
 lqSensorReaderWidget::lqSensorReaderWidget(QWidget *parent) :
   lqSensorWidget(parent)
@@ -14,7 +17,7 @@ lqSensorReaderWidget::lqSensorReaderWidget(QWidget *parent) :
   // In reading mode, we only read the packet received on the right lidarPort.
   // This is why we want to expose it in reader mode too
   this->UI->lidarPort->setVisible(true);
-}
+ }
 
 //-----------------------------------------------------------------------------
 void lqSensorReaderWidget::onUpdateUI()
diff --git a/ApplicationComponents/SensorWidget/lqSensorReaderWidget.h b/ApplicationComponents/SensorWidget/lqSensorReaderWidget.h
index 4c160a2c3..044cecc6a 100644
--- a/ApplicationComponents/SensorWidget/lqSensorReaderWidget.h
+++ b/ApplicationComponents/SensorWidget/lqSensorReaderWidget.h
@@ -9,6 +9,8 @@
 
 class pqPipelineSource;
 
+
+
 /**
  * @brief The lqSensorWidget enable to handle some function of a Lidar with buttons.
  *
@@ -25,6 +27,9 @@ class LQAPPLICATIONCOMPONENTS_EXPORT lqSensorReaderWidget : public lqSensorWidge
   QString GetExplanationOnUI() override;
 
   public slots:
+  /*!
+   * @brief Function slot used to update the text of the UI depending on whether we are in reader or stream mode 
+   */
     void onUpdateUI() override;
 
 private:
diff --git a/ApplicationComponents/SensorWidget/lqSensorWidget.cxx b/ApplicationComponents/SensorWidget/lqSensorWidget.cxx
index b2bb69472..ff92c6c49 100644
--- a/ApplicationComponents/SensorWidget/lqSensorWidget.cxx
+++ b/ApplicationComponents/SensorWidget/lqSensorWidget.cxx
@@ -1,4 +1,5 @@
 #include "lqSensorWidget.h"
+#include "lqHelper.h"
 #include "ui_lqSensorWidget.h"
 
 #include "lqLoadLidarStateReaction.h"
@@ -13,6 +14,7 @@
 #include <vtkSMProperty.h>
 #include <vtkSMPropertyHelper.h>
 #include <vtkSMProxy.h>
+#include <vtkSMSourceProxy.h>
 
 #include "vtkLidarStream.h"
 
@@ -44,6 +46,108 @@ lqSensorWidget::lqSensorWidget(QWidget *parent) :
   this->setFocusPolicy(Qt::StrongFocus);
 
   this->SourceToDisplay = nullptr;
+
+   
+  this->UI->enableLiveDataTransformCheckBox->setVisible(true);
+
+  // set up arrays to point on sliders and spinboxes corresponding to each transform param
+  this->slider_Array[TRANSFORMVALUE_INDEX::POS_X] = this->UI->TxSlider;
+  this->slider_Array[TRANSFORMVALUE_INDEX::POS_Y] = this->UI->TySlider;
+  this->slider_Array[TRANSFORMVALUE_INDEX::POS_Z] = this->UI->TzSlider;
+  this->slider_Array[TRANSFORMVALUE_INDEX::ROT_ROLL] = this->UI->RollSlider;
+  this->slider_Array[TRANSFORMVALUE_INDEX::ROT_PITCH] = this->UI->PitchSlider;
+  this->slider_Array[TRANSFORMVALUE_INDEX::ROT_YAW] = this->UI->YawSlider;
+
+  this->spinbox_Array[TRANSFORMVALUE_INDEX::POS_X] = this->UI->TxSpinBox;
+  this->spinbox_Array[TRANSFORMVALUE_INDEX::POS_Y] = this->UI->TySpinBox;
+  this->spinbox_Array[TRANSFORMVALUE_INDEX::POS_Z] = this->UI->TzSpinBox;
+  this->spinbox_Array[TRANSFORMVALUE_INDEX::ROT_ROLL] = this->UI->RollSpinBox;
+  this->spinbox_Array[TRANSFORMVALUE_INDEX::ROT_PITCH] = this->UI->PitchSpinBox;
+  this->spinbox_Array[TRANSFORMVALUE_INDEX::ROT_YAW] = this->UI->YawSpinBox;
+
+  // Hide UI that shall not be shown if not in live transform mode
+  this->onEnableLiveTransformToggle();
+
+  // init internal values from UI defaults
+  for (unsigned int idxValue = 0; idxValue < TRANSFORMVALUE_INDEX::TRANSFORM_SIZE; idxValue++)
+  {
+    min_Transform[idxValue] = this->spinbox_Array[idxValue]->minimum();
+    max_Transform[idxValue] = this->spinbox_Array[idxValue]->maximum();
+    curr_Transform[idxValue] = this->spinbox_Array[idxValue]->value();
+  }
+
+  connect(this->UI->enableLiveDataTransformCheckBox, &QCheckBox::stateChanged, this,
+    [this] { lqSensorWidget::onEnableLiveTransformToggle(); });
+
+  // Connect Slider movement to transform updating function
+  connect(this->UI->TxSlider, &QSlider::sliderMoved, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::POS_X); });
+  connect(this->UI->TySlider, &QSlider::sliderMoved, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::POS_Y); });
+  connect(this->UI->TzSlider, &QSlider::sliderMoved, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::POS_Z); });
+  connect(this->UI->RollSlider, &QSlider::sliderMoved, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::ROT_ROLL); });
+  connect(this->UI->PitchSlider, &QSlider::sliderMoved, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::ROT_PITCH); });
+  connect(this->UI->YawSlider, &QSlider::sliderMoved, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::ROT_YAW); });
+
+  // connect Slider Release signal to make sur last value of the slider is recorded
+  connect(this->UI->TxSlider, &QSlider::sliderReleased, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::POS_X); });
+  connect(this->UI->TySlider, &QSlider::sliderReleased, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::POS_Y); });
+  connect(this->UI->TzSlider, &QSlider::sliderReleased, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::POS_Z); });
+  connect(this->UI->RollSlider, &QSlider::sliderReleased, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::ROT_ROLL); });
+  connect(this->UI->PitchSlider, &QSlider::sliderReleased, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::ROT_PITCH); });
+  connect(this->UI->YawSlider, &QSlider::sliderReleased, this,
+    [this] { lqSensorWidget::onSliderUpdate(TRANSFORMVALUE_INDEX::ROT_YAW); });
+
+  // connect value spinboxes to corresponding function
+  connect(this->UI->TxSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_X); });
+  connect(this->UI->TySpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_Y); });
+  connect(this->UI->TzSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_Z); });
+  connect(this->UI->RollSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_ROLL); });
+  connect(this->UI->PitchSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_PITCH); });
+  connect(this->UI->YawSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_YAW); });
+
+  // connect min max spin boxes to corresponding function
+  connect(this->UI->MinTranslationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_X); });
+  connect(this->UI->MinTranslationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_Y); });
+  connect(this->UI->MinTranslationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_Z); });
+  connect(this->UI->MinRotationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_ROLL); });
+  connect(this->UI->MinRotationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_PITCH); });
+  connect(this->UI->MinRotationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_YAW); });
+
+  // connect min max spin boxes to corresponding function
+  connect(this->UI->MaxTranslationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_X); });
+  connect(this->UI->MaxTranslationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_Y); });
+  connect(this->UI->MaxTranslationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::POS_Z); });
+  connect(this->UI->MaxRotationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_ROLL); });
+  connect(this->UI->MaxRotationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_PITCH); });
+  connect(this->UI->MaxRotationValueSpinBox, &QDoubleSpinBox::editingFinished, this,
+    [this] { lqSensorWidget::onMinMaxValueSpinBoxUpdate(TRANSFORMVALUE_INDEX::ROT_YAW); });
 }
 
 //-----------------------------------------------------------------------------
@@ -151,6 +255,9 @@ void lqSensorWidget::onCalibrate()
   {
     this->CalibrationFunction(this->LidarSource, this->PositionOrientationSource);
   }
+  // update internal transform based on updated proxy transform
+  ReadValueFromProxy();
+
 }
 
 //-----------------------------------------------------------------------------
@@ -250,3 +357,258 @@ void lqSensorWidget::focusInEvent(QFocusEvent*)
 {
   emit selected(this);
 }
+
+void lqSensorWidget::onEnableLiveTransformToggle()
+{
+  // Get enable flag for the check box
+  bool isLiveTransformVisible = this->UI->enableLiveDataTransformCheckBox->isChecked();
+
+  // set / unset visibility of the tools to move the lidar data
+  this->UI->TranslationLabel->setVisible(isLiveTransformVisible);
+  this->UI->labelMinMaxTranslation->setVisible(isLiveTransformVisible);
+  this->UI->MinTranslationValueSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->MaxTranslationValueSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->TxSlider->setVisible(isLiveTransformVisible);
+  this->UI->TxSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->TySlider->setVisible(isLiveTransformVisible);
+  this->UI->TySpinBox->setVisible(isLiveTransformVisible);
+  this->UI->TzSlider->setVisible(isLiveTransformVisible);
+  this->UI->TzSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->RotationLabel->setVisible(isLiveTransformVisible);
+  this->UI->labelMinMaxRotation->setVisible(isLiveTransformVisible);
+  this->UI->MinRotationValueSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->MaxRotationValueSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->RollSlider->setVisible(isLiveTransformVisible);
+  this->UI->RollSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->PitchSlider->setVisible(isLiveTransformVisible);
+  this->UI->PitchSpinBox->setVisible(isLiveTransformVisible);
+  this->UI->YawSlider->setVisible(isLiveTransformVisible);
+  this->UI->YawSpinBox->setVisible(isLiveTransformVisible);
+
+  ReadValueFromProxy();
+}
+
+void lqSensorWidget::onSliderUpdate(unsigned int idxValue)
+{
+  // get value from slider
+  // update MinMax values
+  if (idxValue <= POS_Z)
+  {
+    min_Transform[idxValue] = this->UI->MinTranslationValueSpinBox->value();
+    max_Transform[idxValue] = this->UI->MaxTranslationValueSpinBox->value();
+  }
+  else
+  {
+    min_Transform[idxValue] = this->UI->MinRotationValueSpinBox->value();
+    max_Transform[idxValue] = this->UI->MaxRotationValueSpinBox->value();
+  }
+
+  // compute value represented by the slider position
+  double sliderRange = std::max(
+    static_cast<double>(slider_Array[idxValue]->maximum() - slider_Array[idxValue]->minimum()),
+    1.0);
+  double value =
+    (static_cast<double>((slider_Array[idxValue]->value() - slider_Array[idxValue]->minimum())) /
+      sliderRange) *
+      (max_Transform[idxValue] - min_Transform[idxValue]) +
+    min_Transform[idxValue];
+
+  // update internal value
+  curr_Transform[idxValue] = value;
+
+  // update corresponding spinbox
+  this->spinbox_Array[idxValue]->setValue(value);
+
+  // call update transform
+  onUpdateTransform();
+}
+
+void lqSensorWidget::onValueSpinBoxUpdate(unsigned int idxValue)
+{
+  // update internal value
+  curr_Transform[idxValue] = this->spinbox_Array[idxValue]->value();
+  // update slider position based on scaling
+  int sliderPosition = slider_Array[idxValue]->minimum() +
+    ((slider_Array[idxValue]->maximum() - slider_Array[idxValue]->minimum()) *
+      (curr_Transform[idxValue] - min_Transform[idxValue]) /
+      (max_Transform[idxValue] - min_Transform[idxValue]));
+  this->slider_Array[idxValue]->setValue(sliderPosition);
+
+  // call update transform
+  onUpdateTransform();
+}
+
+void lqSensorWidget::onMinMaxValueSpinBoxUpdate(unsigned int idxValue)
+{
+  // update MinMax values ( assumption is that first values are translation then rotation, in
+  // X,Y,Z,Roll,Pitch,Yaw order)
+  if (idxValue <= POS_Z)
+  {
+    min_Transform[idxValue] = this->UI->MinTranslationValueSpinBox->value();
+    max_Transform[idxValue] = this->UI->MaxTranslationValueSpinBox->value();
+  }
+  else
+  {
+    min_Transform[idxValue] = this->UI->MinRotationValueSpinBox->value();
+    max_Transform[idxValue] = this->UI->MaxRotationValueSpinBox->value();
+  }
+  // Saturate internal values
+  if (min_Transform[idxValue] > curr_Transform[idxValue])
+  {
+    curr_Transform[idxValue] = min_Transform[idxValue];
+  }
+  if (max_Transform[idxValue] < curr_Transform[idxValue])
+  {
+    curr_Transform[idxValue] = max_Transform[idxValue];
+  }
+
+  // update widgets
+  UpdateSpinBoxAndSliderFromInternalValues(idxValue);
+
+  // call update transform
+  onUpdateTransform();
+}
+
+void lqSensorWidget::UpdateSpinBoxAndSliderFromInternalValues(unsigned int idxValue)
+{
+  // update spinbox min and max
+  this->spinbox_Array[idxValue]->setMinimum(min_Transform[idxValue]);
+  this->spinbox_Array[idxValue]->setMaximum(max_Transform[idxValue]);
+
+  // update spinbox / slider position based on scaling
+  this->spinbox_Array[idxValue]->setValue(curr_Transform[idxValue]);
+
+  int sliderPosition = slider_Array[idxValue]->minimum() +
+    ((slider_Array[idxValue]->maximum() - slider_Array[idxValue]->minimum()) *
+      (curr_Transform[idxValue] - min_Transform[idxValue]) /
+      (max_Transform[idxValue] - min_Transform[idxValue]));
+  this->slider_Array[idxValue]->setValue(sliderPosition);
+}
+
+void lqSensorWidget::ReadValueFromProxy()
+{
+  // Get lidar proxy
+  if (this->LidarSource)
+  {
+    vtkSMProxy* lidarProxy = this->LidarSource->getProxy();
+
+    // names of the lidarreader proxy
+    std::string propertyNameTranslation = "Position";
+    std::string propertyNameRotation = "Rotation";
+    std::string TransformproxyName = "Transform2";
+
+    if (lidarProxy)
+    {
+      // Get transform proxy
+      vtkSMProxy* TransformProxy = SearchProxyByName(lidarProxy, TransformproxyName);
+      // Get translation property
+      vtkSMProperty* propTranslation =
+        GetPropertyFromProxy(TransformProxy, propertyNameTranslation);
+      std::vector<double> TranslationVector = vtkSMPropertyHelper(propTranslation).GetDoubleArray();
+
+      // Get Translation parameters
+      double Tx = TranslationVector[0];
+      double Ty = TranslationVector[1];
+      double Tz = TranslationVector[2];
+
+      // Get translation property
+      vtkSMProperty* propRotation = GetPropertyFromProxy(TransformProxy, propertyNameRotation);
+      std::vector<double> RotationVector = vtkSMPropertyHelper(propRotation).GetDoubleArray();
+      // Get Rotation parameters
+      double Roll = RotationVector[0];
+      double Pitch = RotationVector[1];
+      double Yaw = RotationVector[2];
+
+      // Concatenate them in a vector
+      double TransformParams[TRANSFORMVALUE_INDEX::TRANSFORM_SIZE] = { Tx, Ty, Tz, Roll, Pitch,
+        Yaw };
+
+      // update internal values
+      // Get current min and max for rotation and translation
+      double minMinTranslation = this->UI->MinTranslationValueSpinBox->value();
+      double maxMaxTranslation = this->UI->MaxTranslationValueSpinBox->value();
+      double minMinRotation = this->UI->MinRotationValueSpinBox->value();
+      double maxMaxRotation = this->UI->MaxRotationValueSpinBox->value();
+
+      // Loop over parameters to update the current values with what is found  on the proxy
+      for (unsigned int idxValue = 0; idxValue < TRANSFORMVALUE_INDEX::TRANSFORM_SIZE; idxValue++)
+      {
+        // update current value
+        curr_Transform[idxValue] = TransformParams[idxValue];
+
+        // update min and max if necessary
+        min_Transform[idxValue] = std::min(min_Transform[idxValue], curr_Transform[idxValue]);
+        max_Transform[idxValue] = std::max(max_Transform[idxValue], curr_Transform[idxValue]);
+        this->spinbox_Array[idxValue]->setMinimum(min_Transform[idxValue]);
+        this->spinbox_Array[idxValue]->setMaximum(max_Transform[idxValue]);
+
+        // collect overall minimum and maximum to be able to update the min and max spinboxes
+        if (idxValue <= POS_Z)
+        {
+          minMinTranslation = std::min(minMinTranslation, min_Transform[idxValue]);
+          maxMaxTranslation = std::max(maxMaxTranslation, max_Transform[idxValue]);
+        }
+        else
+        {
+          minMinRotation = std::min(minMinRotation, min_Transform[idxValue]);
+          maxMaxRotation = std::max(maxMaxRotation, max_Transform[idxValue]);
+        }
+        // update spinbox and slider
+        UpdateSpinBoxAndSliderFromInternalValues(idxValue);
+
+      } // End for loop on transforms
+
+      // set min and max spinboxes with the minimum found
+      this->UI->MinTranslationValueSpinBox->setValue(minMinTranslation);
+      this->UI->MaxTranslationValueSpinBox->setValue(maxMaxTranslation);
+      this->UI->MinRotationValueSpinBox->setValue(minMinRotation);
+      this->UI->MaxRotationValueSpinBox->setValue(maxMaxRotation);
+
+    } // end if lidarProxy
+  }   // end if LidarSource
+}
+
+void lqSensorWidget::onUpdateTransform()
+{
+  vtkSMProxy* lidarProxy = this->LidarSource->getProxy();
+
+  // names of the lidarreader proxy
+  std::string propertyNameTranslation = "Position";
+  std::string propertyNameRotation = "Rotation";
+  std::string TransformproxyName = "Transform2";
+
+  if (lidarProxy)
+  {
+    // Recover translation from sliders
+    double Tx = curr_Transform[TRANSFORMVALUE_INDEX::POS_X];
+    double Ty = curr_Transform[TRANSFORMVALUE_INDEX::POS_Y];
+    double Tz = curr_Transform[TRANSFORMVALUE_INDEX::POS_Z];
+    std::vector<std::string> TranslationValues = { std::to_string(Tx), std::to_string(Ty),
+      std::to_string(Tz) };
+
+    // Recover Rotation from sliders
+    double Roll = curr_Transform[TRANSFORMVALUE_INDEX::ROT_ROLL];
+    double Pitch = curr_Transform[TRANSFORMVALUE_INDEX::ROT_PITCH];
+    double Yaw = curr_Transform[TRANSFORMVALUE_INDEX::ROT_YAW];
+    std::vector<std::string> RotationValues = { std::to_string(Roll), std::to_string(Pitch),
+      std::to_string(Yaw) };
+
+    // Get transform proxy
+    vtkSMProxy* TransformProxy = SearchProxyByName(lidarProxy, TransformproxyName);
+
+    // update proxy properties
+    vtkSMProperty* prop = GetPropertyFromProxy(TransformProxy, propertyNameTranslation);
+    UpdateProxyProperty(TransformProxy, propertyNameTranslation, TranslationValues);
+
+    prop = GetPropertyFromProxy(TransformProxy, propertyNameRotation);
+    UpdateProxyProperty(TransformProxy, propertyNameRotation, RotationValues);
+
+    lidarProxy->UpdateSelfAndAllInputs();
+    vtkSMSourceProxy* sourcelidarProxy = vtkSMSourceProxy::SafeDownCast(lidarProxy);
+    if (sourcelidarProxy)
+    {
+      sourcelidarProxy->UpdatePipelineInformation();
+    }
+    pqApplicationCore::instance()->render();
+  }
+}
diff --git a/ApplicationComponents/SensorWidget/lqSensorWidget.h b/ApplicationComponents/SensorWidget/lqSensorWidget.h
index 82d9ba194..3d1dbddfa 100644
--- a/ApplicationComponents/SensorWidget/lqSensorWidget.h
+++ b/ApplicationComponents/SensorWidget/lqSensorWidget.h
@@ -4,6 +4,8 @@
 #include "lqapplicationcomponents_export.h"
 
 #include <QWidget>
+#include <QSlider>
+#include <QDoubleSpinBox>
 #include <functional>
 
 class pqPipelineSource;
@@ -23,6 +25,19 @@ class LQAPPLICATIONCOMPONENTS_EXPORT lqSensorWidget : public QWidget
 {
   Q_OBJECT
 
+  // method to identify the normal of the plane containing the turn
+  enum TRANSFORMVALUE_INDEX
+  {
+    POS_X = 0,
+    POS_Y = 1,
+    POS_Z = 2,
+    ROT_ROLL = 3,
+    ROT_PITCH = 4,
+    ROT_YAW = 5,
+    TRANSFORM_SIZE = 6
+  };
+
+
   public:
     explicit lqSensorWidget(QWidget *parent = 0);
     ~lqSensorWidget();
@@ -46,6 +61,12 @@ class LQAPPLICATIONCOMPONENTS_EXPORT lqSensorWidget : public QWidget
 
     virtual QString GetExplanationOnUI() = 0;
 
+    /*!
+    * @brief Function used to get the transfrom data from a proxy and update the internal data /
+    * spinbox and sliders of this class accordingly
+    */
+    void ReadValueFromProxy();
+
   public slots:
     virtual void onUpdateUI();
     void onCalibrate();
@@ -54,6 +75,36 @@ class LQAPPLICATIONCOMPONENTS_EXPORT lqSensorWidget : public QWidget
     void onSaveLidarState();
     void onLoadLidarState();
 
+  protected slots:
+    /*!
+     * @brief Function slot used to update the transform of the lidarsource based on the data
+     * entered in the UI
+     */
+    void onUpdateTransform();
+    /*!
+     * @brief Function slot used to react to an update of a spinbox of a value
+     * This will store the data entered in internal variables, update the associated slider
+     * accordingly and update the transform
+     */
+    void onValueSpinBoxUpdate(unsigned int idxValue);
+    /*!
+     * @brief Function slot used to react to an update of a slider of a value. This will update the
+     * internal variables for this and update the transform
+     */
+    void onSliderUpdate(unsigned int idxValue);
+    /*!
+     * @brief Function slot used to react of an update of the min / max spinboxes for translations
+     * or rotations This will saturate the values used in the transform and update spinboxes /
+     * sliders accordingly
+     */
+    void onMinMaxValueSpinBoxUpdate(unsigned int idxValue);
+    /*!
+     * @brief Function slot used to react on the toggling of the check box to enable or not the live
+     * transform This will hide / show the whole interface and read the data from the proxy to feed
+     * to the interface
+     */
+    void onEnableLiveTransformToggle();
+
 signals:
     void selected(lqSensorWidget*);
 
@@ -69,6 +120,27 @@ protected:
     bool IsClosing;
     Ui::lqSensorWidget* UI;
     std::function<void(pqPipelineSource* &, pqPipelineSource* &)> CalibrationFunction;
+
+    
+    /*!
+     * @brief common function to update internal QT widgets to internal values
+     */
+    void UpdateSpinBoxAndSliderFromInternalValues(unsigned int idxValue);
+
+    // maximum value for the sliders scaling
+    double min_Transform[TRANSFORMVALUE_INDEX::TRANSFORM_SIZE]; // in order : X,Y,Z,Roll,Pitch,Yaw
+
+    // minimum value for the slider / spinbox scaling
+    double max_Transform[TRANSFORMVALUE_INDEX::TRANSFORM_SIZE]; // in order : X,Y,Z,Roll,Pitch,Yaw
+
+    // current value for each transform
+    double curr_Transform[TRANSFORMVALUE_INDEX::TRANSFORM_SIZE]; // in order : X,Y,Z,Roll,Pitch,Yaw
+
+    // current value for each transform
+    QSlider* slider_Array[TRANSFORMVALUE_INDEX::TRANSFORM_SIZE]; // in order : X,Y,Z,Roll,Pitch,Yaw
+
+    // current value for each transform
+    QDoubleSpinBox* spinbox_Array[TRANSFORMVALUE_INDEX::TRANSFORM_SIZE]; // in order : X,Y,Z,Roll,Pitch,Yaw
 };
 
 #endif // LQSENSORWIDGET_H
diff --git a/ApplicationComponents/SensorWidget/lqSensorWidget.ui b/ApplicationComponents/SensorWidget/lqSensorWidget.ui
index 5d43b31e5..c2be0832c 100644
--- a/ApplicationComponents/SensorWidget/lqSensorWidget.ui
+++ b/ApplicationComponents/SensorWidget/lqSensorWidget.ui
@@ -6,12 +6,12 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>330</width>
-    <height>150</height>
+    <width>334</width>
+    <height>300</height>
    </rect>
   </property>
   <property name="sizePolicy">
-   <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+   <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
     <horstretch>0</horstretch>
     <verstretch>0</verstretch>
    </sizepolicy>
@@ -19,13 +19,13 @@
   <property name="minimumSize">
    <size>
     <width>330</width>
-    <height>150</height>
+    <height>225</height>
    </size>
   </property>
   <property name="maximumSize">
    <size>
     <width>16777215</width>
-    <height>300</height>
+    <height>500</height>
    </size>
   </property>
   <property name="windowTitle">
@@ -323,6 +323,441 @@
         </item>
        </layout>
       </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_7">
+          <item>
+           <widget class="QCheckBox" name="enableLiveDataTransformCheckBox">
+            <property name="layoutDirection">
+             <enum>Qt::RightToLeft</enum>
+            </property>
+            <property name="text">
+             <string>Enable Live Data Transform</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_12">
+          <item>
+           <widget class="QLabel" name="TranslationLabel">
+            <property name="toolTip">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Translate the data in X,Y, and Z directions within boundaries defined by Min and Max value. You may use the sliders of the boxes below to change the values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="text">
+             <string>Translation [X;Y;Z]</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_17">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::MinimumExpanding</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="labelMinMaxTranslation">
+            <property name="text">
+             <string>[Min;Max]</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="MinTranslationValueSpinBox">
+            <property name="minimum">
+             <double>-2000.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>2000.000000000000000</double>
+            </property>
+            <property name="value">
+             <double>-5.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="MaxTranslationValueSpinBox">
+            <property name="minimum">
+             <double>-2000.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>2000.000000000000000</double>
+            </property>
+            <property name="value">
+             <double>5.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="LayoutTranslationSliders">
+          <item>
+           <widget class="QSlider" name="TxSlider">
+            <property name="minimum">
+             <number>-50</number>
+            </property>
+            <property name="maximum">
+             <number>50</number>
+            </property>
+            <property name="value">
+             <number>0</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_8">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="TxSpinBox">
+            <property name="minimum">
+             <double>-5.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>5.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_5">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>10</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QSlider" name="TySlider">
+            <property name="minimum">
+             <number>-50</number>
+            </property>
+            <property name="maximum">
+             <number>50</number>
+            </property>
+            <property name="value">
+             <number>0</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_9">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="TySpinBox">
+            <property name="minimum">
+             <double>-5.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>5.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_4">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>10</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QSlider" name="TzSlider">
+            <property name="minimum">
+             <number>-50</number>
+            </property>
+            <property name="maximum">
+             <number>50</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_10">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="TzSpinBox">
+            <property name="minimum">
+             <double>-5.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>5.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_9">
+          <item>
+           <widget class="QLabel" name="RotationLabel">
+            <property name="toolTip">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rotate the data according to base axis with values defined between min and max values&lt;/p&gt;&lt;p&gt;Roll corresponds to rotation around the X axis&lt;/p&gt;&lt;p&gt;Pitch corresponds to rotation around the Y axis&lt;/p&gt;&lt;p&gt;Yaw corresponds to rotation around the Z axis &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="text">
+             <string>Rotation [Roll;Pitch;Yaw]</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_16">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::MinimumExpanding</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="labelMinMaxRotation">
+            <property name="text">
+             <string>[Min;Max]</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="MinRotationValueSpinBox">
+            <property name="maximum">
+             <double>360.000000000000000</double>
+            </property>
+            <property name="singleStep">
+             <double>1.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="MaxRotationValueSpinBox">
+            <property name="maximum">
+             <double>360.000000000000000</double>
+            </property>
+            <property name="singleStep">
+             <double>1.000000000000000</double>
+            </property>
+            <property name="value">
+             <double>360.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="LayoutRotationSliders">
+          <item>
+           <widget class="QSlider" name="RollSlider">
+            <property name="minimum">
+             <number>-500</number>
+            </property>
+            <property name="maximum">
+             <number>500</number>
+            </property>
+            <property name="value">
+             <number>-500</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_11">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="RollSpinBox">
+            <property name="minimum">
+             <double>0.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>360.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_6">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>10</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QSlider" name="PitchSlider">
+            <property name="minimum">
+             <number>-500</number>
+            </property>
+            <property name="maximum">
+             <number>500</number>
+            </property>
+            <property name="value">
+             <number>-500</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_12">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="PitchSpinBox">
+            <property name="minimum">
+             <double>0.000000000000000</double>
+            </property>
+            <property name="maximum">
+             <double>360.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_7">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>10</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QSlider" name="YawSlider">
+            <property name="maximumSize">
+             <size>
+              <width>16777215</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="minimum">
+             <number>-500</number>
+            </property>
+            <property name="maximum">
+             <number>500</number>
+            </property>
+            <property name="value">
+             <number>-500</number>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer_13">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QDoubleSpinBox" name="YawSpinBox">
+            <property name="maximum">
+             <double>360.000000000000000</double>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </item>
       <item>
        <spacer name="verticalSpacer">
         <property name="orientation">
@@ -418,24 +853,24 @@
         </item>
         <item>
          <widget class="QPushButton" name="SaveLidarState">
+          <property name="toolTip">
+           <string>Save Lidar state</string>
+          </property>
           <property name="icon">
-            <iconset resource="../LVCore/ApplicationComponents/lqResources.qrc">
+           <iconset>
             <normaloff>:/lqResources/Icons/pqSaveState.png</normaloff>:/lqResources/Icons/pqSaveState.png</iconset>
           </property>
-          <property name="toolTip">
-            <string>Save Lidar state</string>
-          </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="LoadLidarState">
+          <property name="toolTip">
+           <string>Load Lidar state</string>
+          </property>
           <property name="icon">
-            <iconset resource="../LVCore/ApplicationComponents/lqResources.qrc">
+           <iconset>
             <normaloff>:/lqResources/Icons/pqLoadState.png</normaloff>:/lqResources/Icons/pqLoadState.png</iconset>
           </property>
-          <property name="toolTip">
-            <string>Load Lidar state</string>
-          </property>
          </widget>
         </item>
         <item>
diff --git a/ApplicationComponents/lqHelper.cxx b/ApplicationComponents/lqHelper.cxx
index 7dfaa4c8f..99b150670 100644
--- a/ApplicationComponents/lqHelper.cxx
+++ b/ApplicationComponents/lqHelper.cxx
@@ -222,6 +222,75 @@ vtkSMProperty* GetPropertyFromProxy(vtkSMProxy * proxy, const std::string &propN
   return nullptr;
 }
 
+//-----------------------------------------------------------------------------
+int UpdateProxyProperty(vtkSMProxy* proxy, const std::string& propNameToFind, const std::vector<std::string>& values)
+{
+  // If there is no value to set, the request is skipped
+  if (values.empty())
+  {
+    std::string message = "Property " + propNameToFind + " couldn't be applied";
+    QMessageBox::information(nullptr, QObject::tr(""), QObject::tr(message.c_str()));
+    return 0;
+  }
+
+  vtkSMProperty* prop = GetPropertyFromProxy(proxy, propNameToFind);
+
+  if (!prop)
+  {
+    return 0;
+  }
+
+  std::vector<double> propertyAsDoubleArray = vtkSMPropertyHelper(prop).GetDoubleArray();
+  if (propertyAsDoubleArray.size() > 1)
+  {
+    if (propertyAsDoubleArray.size() != values.size())
+    {
+      std::cout << "Values to applied and base property does not have the same size" << std::endl;
+    }
+    std::vector<double> d;
+    for (unsigned int j = 0; j < values.size(); j++)
+    {
+      d.push_back(std::stod(values[j]));
+    }
+    vtkSMPropertyHelper(prop).Set(d.data(), d.size());
+    proxy->UpdateProperty(propNameToFind.c_str());
+    return 1;
+  }
+  else
+  {
+    // If the property is a valid variant we display it to the user
+    vtkVariant propertyAsVariant = vtkSMPropertyHelper(prop).GetAsVariant(0);
+    if (propertyAsVariant.IsValid())
+    {
+      if (propertyAsVariant.IsInt())
+      {
+        vtkSMBooleanDomain* boolDomain =
+          vtkSMBooleanDomain::SafeDownCast(prop->FindDomain("vtkSMBooleanDomain"));
+        if (boolDomain && (values[0].compare("false") == 0 || values[0].compare("true") == 0))
+        {
+          int value = (values[0].compare("false") == 0) ? 0 : 1;
+          vtkSMPropertyHelper(prop).Set(value);
+        }
+        else
+        {
+          vtkSMPropertyHelper(prop).Set(std::stoi(values[0]));
+        }
+      }
+      else if (propertyAsVariant.IsNumeric())
+      {
+        vtkSMPropertyHelper(prop).Set(std::stof(values[0]));
+      }
+      else if (propertyAsVariant.IsString())
+      {
+        vtkSMPropertyHelper(prop).Set(values[0].c_str());
+      }
+      proxy->UpdateProperty(propNameToFind.c_str());
+      return 1;
+    }
+  }
+  return 0;
+}
+
 std::string GetGroupName(vtkSMProxy * existingProxy, const std::string & proxyToFindName)
 {
   vtkSMSessionProxyManager* pxm = existingProxy->GetSessionProxyManager();
diff --git a/ApplicationComponents/lqHelper.h b/ApplicationComponents/lqHelper.h
index ec4affe1e..75ca0325f 100644
--- a/ApplicationComponents/lqHelper.h
+++ b/ApplicationComponents/lqHelper.h
@@ -140,6 +140,19 @@ std::vector<vtkSMProxy*> GetLidarsProxy();
  */
 vtkSMProperty* GetPropertyFromProxy(vtkSMProxy * proxy, const std::string &propNameToFind);
 
+
+  /**
+ * @brief UpdateProxyProperty set the values to the property "propNameToFind" of the proxy
+ *        If the property is not found in the proxy, a message is displayed but nothing is done.
+ *        This function is useful, if the property type is unknown.
+ *        If it is known, you should directly use vtkSMPropertyHelper to set the property
+ * @param proxy proxy where to search the property
+ * @param propNameToFind name of the property
+ * @param values properties values to set
+ * @return 1 if the property has been well set, 0 otherwise
+ */
+int UpdateProxyProperty(vtkSMProxy* proxy, const std::string& propNameToFind, const std::vector<std::string>& values);
+
 /**
  * @brief GetGroupName Get the name of the first group where appear a proxy
  * @param existingProxy a proxy of the pipeline, use to get the ProxyDefinitionManager
-- 
GitLab