Procházet zdrojové kódy

Fix ctkVTKThresholdWidget behavior

There was some issues when points where confounded and vtkPiecewiseFunction
doesn't allow duplicates.

Newly exposed methods:
ctkVTKThresholdWidget::thresholdValues
ctkVTKThresholdWidget::opacity
Julien Finet před 14 roky
rodič
revize
4d678b5df9

+ 104 - 45
Libs/Visualization/VTK/Widgets/ctkVTKThresholdWidget.cpp

@@ -46,10 +46,13 @@ public:
 
   void setThreshold(double min, double max, double opacity);
   void setRange(double min, double max);
-  void guessThreshold(double& min, double& max, double& opacity);
+  void guessThreshold(double& min, double& max, double& opacity)const;
   
   vtkPiecewiseFunction* PiecewiseFunction;
   bool UserRange;
+protected:
+  void setNodes(double nodeValues[4][4]);
+  void setNodeValue(int index, double* nodeValue);
 };
 
 // ----------------------------------------------------------------------------
@@ -78,7 +81,7 @@ void ctkVTKThresholdWidgetPrivate::setupUi(QWidget* widget)
 }
 
 // ----------------------------------------------------------------------------
-void ctkVTKThresholdWidgetPrivate::guessThreshold(double& min, double& max, double& opacity)
+void ctkVTKThresholdWidgetPrivate::guessThreshold(double& min, double& max, double& opacity)const
 {
   min = this->ThresholdSliderWidget->minimum();
   max = this->ThresholdSliderWidget->maximum();
@@ -140,62 +143,99 @@ void ctkVTKThresholdWidgetPrivate::setRange(double min, double max)
 // ----------------------------------------------------------------------------
 void ctkVTKThresholdWidgetPrivate::setThreshold(double min, double max, double opacity)
 {
+  Q_Q(ctkVTKThresholdWidget);
   if (!this->PiecewiseFunction)
     {
     return;
     }
+
   double range[2];
   this->ThresholdSliderWidget->range(range);
- 
-  double node[4];
-  node[0] = range[0];
-  node[1] = 0.;
-  node[2] = 0.5;
-  node[3] = 0.;
-  if (this->PiecewiseFunction->GetSize() < 1)
-    {
-    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
-    }
-  else
-    {
-    this->PiecewiseFunction->SetNodeValue(0, node);
-    }
 
-  node[0] = min;
-  node[1] = 0.;
-  node[2] = 0.;
-  node[3] = 1.;
-  if (this->PiecewiseFunction->GetSize() < 2)
-    {
-    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
-    }
-  else
-    {
-    this->PiecewiseFunction->SetNodeValue(1, node);
-    }
-  node[0] = max;
-  node[1] = opacity;
-  if (this->PiecewiseFunction->GetSize() < 3)
-    {
-    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
-    }
-  else
+  // Start of the curve, always y=0
+  double nodes[4][4];
+  nodes[0][0] = range[0];
+  nodes[0][1] = 0.;
+  nodes[0][2] = 0.5; // midpoint
+  nodes[0][3] = 0.; // sharpness
+
+  // Starting threshold point with a sharp slope that jumps to the opacity
+  // which is set by the next point
+  nodes[1][0] = min  +
+    ((min == nodes[0][0] && !this->PiecewiseFunction->GetAllowDuplicateScalars()) ?
+      0.00000000000001 : 0.);
+  nodes[1][1] = 0.;
+  nodes[1][2] = 0.; // jumps directly
+  nodes[1][3] = 1.; // sharp
+
+  // Ending threshold point with a sharp slope that jumps back to a 0 opacity
+  nodes[2][0] = max +
+    ((max == nodes[1][0] && !this->PiecewiseFunction->GetAllowDuplicateScalars()) ?
+      0.00000000000001 : 0.);
+  nodes[2][1] = opacity;
+  nodes[2][2] = 0.;
+  nodes[2][3] = 1.;
+
+  // End of the curve, always y = 0
+  nodes[3][0] = range[1] +
+   ((range[1] == nodes[2][0] && !this->PiecewiseFunction->GetAllowDuplicateScalars()) ?
+      0.00000000000001 : 0.);
+  nodes[3][1] = 0.;
+  nodes[3][2] = 0.5;
+  nodes[3][3] = 0.;
+
+  q->qvtkBlock(this->PiecewiseFunction, vtkCommand::ModifiedEvent, q);
+  this->setNodes(nodes);
+  q->qvtkUnblock(this->PiecewiseFunction, vtkCommand::ModifiedEvent, q);
+  q->updateFromPiecewiseFunction();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidgetPrivate::setNodes(double nodeValues[4][4])
+{
+  double lastX = VTK_DOUBLE_MIN;
+  double minX = nodeValues[0][0];
+  for(int i = 0; i < 4; ++i)
     {
-    this->PiecewiseFunction->SetNodeValue(2, node);
+    int index = this->PiecewiseFunction->GetSize();
+    bool alreadyEqual = false;
+    // search the node index to modify
+    for (int j = 0; j < this->PiecewiseFunction->GetSize(); ++j)
+      {
+      double node[4];
+      this->PiecewiseFunction->GetNodeValue(j, node);
+      if (node[0] < minX || node[0] > lastX)
+        {
+        index = j;
+        break;
+        }
+      else if (node[0] == lastX)
+        {
+        if (alreadyEqual)
+          {
+          index = j;
+          break;
+          }
+        alreadyEqual = true;
+        }
+      }
+    this->setNodeValue(index, nodeValues[i]);
+    lastX = nodeValues[i][0];
     }
-  node[0] = (max == range[1]) ? range[1] + 0.00000000000001 : range[1];
-  node[1] = 0.;
-  node[2] = 0.5;
-  node[3] = 0.;
-  if (this->PiecewiseFunction->GetSize() < 4)
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidgetPrivate::setNodeValue(int index, double* nodeValues)
+{
+  if (this->PiecewiseFunction->GetSize() <= index)
     {
-    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
+    this->PiecewiseFunction->AddPoint(
+      nodeValues[0], nodeValues[1], nodeValues[2], nodeValues[3]);
     }
   else
     {
-    this->PiecewiseFunction->SetNodeValue(3, node);
+    this->PiecewiseFunction->SetNodeValue(index, nodeValues);
     }
-
 }
 
 // ----------------------------------------------------------------------------
@@ -265,7 +305,7 @@ void ctkVTKThresholdWidget::updateFromPiecewiseFunction()
   d->ThresholdSliderWidget->range(range);
   double minThreshold = range[0];
   double maxThreshold = range[1];
-  double opacity = 1.;
+  double opacity = d->OpacitySliderWidget->value();
   double node[4];
   if (d->PiecewiseFunction->GetSize() > 1)
     {
@@ -278,6 +318,10 @@ void ctkVTKThresholdWidget::updateFromPiecewiseFunction()
     maxThreshold = node[0];
     opacity = node[1];
     }
+  if (d->PiecewiseFunction->GetSize() > 3)
+    {
+    d->PiecewiseFunction->GetNodeValue(3, node);
+    }
   bool wasBlocking = d->ThresholdSliderWidget->blockSignals(true);
   d->ThresholdSliderWidget->setValues(minThreshold, maxThreshold);
   d->ThresholdSliderWidget->blockSignals(wasBlocking);
@@ -294,6 +338,14 @@ void ctkVTKThresholdWidget::setThresholdValues(double min, double max)
 }
 
 // ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget::thresholdValues(double* values)const
+{
+  Q_D(const ctkVTKThresholdWidget);
+  values[0] = d->ThresholdSliderWidget->minimumValue();
+  values[1] = d->ThresholdSliderWidget->maximumValue();
+}
+
+// ----------------------------------------------------------------------------
 void ctkVTKThresholdWidget::setOpacity(double opacity)
 {
   Q_D(ctkVTKThresholdWidget);
@@ -302,6 +354,13 @@ void ctkVTKThresholdWidget::setOpacity(double opacity)
 }
 
 // ----------------------------------------------------------------------------
+double ctkVTKThresholdWidget::opacity()const
+{
+  Q_D(const ctkVTKThresholdWidget);
+  return d->OpacitySliderWidget->value();
+}
+
+// ----------------------------------------------------------------------------
 void ctkVTKThresholdWidget::range(double* range)const
 {
   Q_D(const ctkVTKThresholdWidget);

+ 8 - 3
Libs/Visualization/VTK/Widgets/ctkVTKThresholdWidget.h

@@ -37,22 +37,27 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKThresholdWidget
 {
   Q_OBJECT
   QVTK_OBJECT
-
+  /// Setting the opacity property has no effect when no piecewise function is
+  /// set.
+  Q_PROPERTY(double opacity READ opacity WRITE setOpacity DESIGNABLE false)
 public:
   ctkVTKThresholdWidget(QWidget* parent = 0);
   virtual ~ctkVTKThresholdWidget();
 
   vtkPiecewiseFunction* piecewiseFunction()const;
+
   void range(double* range)const;
+  void thresholdValues(double* values)const;
+  double opacity()const;
 
 public slots:
   void setPiecewiseFunction(vtkPiecewiseFunction* function);
   void setRange(double min, double max);
+  void setThresholdValues(double min, double max);
+  void setOpacity(double opacity);
 
 protected slots:
   void updateFromPiecewiseFunction();
-  void setThresholdValues(double min, double max);
-  void setOpacity(double opacity);
 
 protected:
   QScopedPointer<ctkVTKThresholdWidgetPrivate> d_ptr;