123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /*=========================================================================
- Library: CTK
- Copyright (c) Kitware Inc.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0.txt
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- =========================================================================*/
- // Qt includes
- #include <QDebug>
- // CTK includes
- #include "ctkLogger.h"
- #include "ctkVTKThresholdWidget.h"
- #include "ctkUtils.h"
- #include "ui_ctkVTKThresholdWidget.h"
- // VTK includes
- #include <vtkPiecewiseFunction.h>
- //----------------------------------------------------------------------------
- static ctkLogger logger("org.commontk.visualization.vtk.widgets.ctkVTKThresholdWidget");
- //----------------------------------------------------------------------------
- class ctkVTKThresholdWidgetPrivate:
- public Ui_ctkVTKThresholdWidget
- {
- Q_DECLARE_PUBLIC(ctkVTKThresholdWidget);
- protected:
- ctkVTKThresholdWidget* const q_ptr;
- public:
- ctkVTKThresholdWidgetPrivate(ctkVTKThresholdWidget& object);
- void setupUi(QWidget* widget);
- void setThreshold(double min, double max, double opacity);
- void setRange(double min, double max);
- 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);
- };
- // ----------------------------------------------------------------------------
- // ctkVTKThresholdWidgetPrivate methods
- // ----------------------------------------------------------------------------
- ctkVTKThresholdWidgetPrivate::ctkVTKThresholdWidgetPrivate(
- ctkVTKThresholdWidget& object)
- : q_ptr(&object)
- {
- this->PiecewiseFunction = 0;
- this->UserRange = false;
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidgetPrivate::setupUi(QWidget* widget)
- {
- Q_Q(ctkVTKThresholdWidget);
- Q_ASSERT(q == widget);
- this->Ui_ctkVTKThresholdWidget::setupUi(widget);
- QObject::connect(this->ThresholdSliderWidget, SIGNAL(valuesChanged(double,double)),
- q, SLOT(setThresholdValues(double,double)));
- QObject::connect(this->OpacitySliderWidget, SIGNAL(valueChanged(double)),
- q, SLOT(setOpacity(double)));
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidgetPrivate::guessThreshold(double& min, double& max, double& opacity)const
- {
- min = this->ThresholdSliderWidget->minimum();
- max = this->ThresholdSliderWidget->maximum();
- opacity = 1.;
- if (!this->PiecewiseFunction || this->PiecewiseFunction->GetSize() == 0)
- {
- return;
- }
- int minIndex;
- for (minIndex=0; minIndex < this->PiecewiseFunction->GetSize(); ++minIndex)
- {
- double node[4];
- this->PiecewiseFunction->GetNodeValue(minIndex, node);
- if (node[1] > 0.)
- {
- min = node[0];
- opacity = node[1];
- break;
- }
- }
- if (minIndex == this->PiecewiseFunction->GetSize())
- {
- return;
- }
- int maxIndex;
- for (maxIndex = minIndex + 1;
- maxIndex < this->PiecewiseFunction->GetSize();
- ++maxIndex)
- {
- double node[4];
- this->PiecewiseFunction->GetNodeValue(maxIndex, node);
- // average the opacities
- opacity += node[1];
- if (node[1] == 0.)
- {
- max = node[0];
- opacity /= maxIndex - minIndex + 1;
- break;
- }
- }
- // couldn't find the upper threshold value, use the upper range
- if (maxIndex == this->PiecewiseFunction->GetSize())
- {
- opacity /= maxIndex - minIndex;
- }
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidgetPrivate::setRange(double min, double max)
- {
- bool wasBlocking = this->ThresholdSliderWidget->blockSignals(true);
- int decimals = qMax(0, -ctk::orderOfMagnitude(max - min) + 2);
- this->ThresholdSliderWidget->setDecimals(decimals);
- this->ThresholdSliderWidget->setSingleStep(pow(10., -decimals));
- this->ThresholdSliderWidget->setRange(min, max);
- this->ThresholdSliderWidget->blockSignals(wasBlocking);
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidgetPrivate::setThreshold(double min, double max, double opacity)
- {
- Q_Q(ctkVTKThresholdWidget);
- if (!this->PiecewiseFunction)
- {
- return;
- }
- double range[2];
- this->ThresholdSliderWidget->range(range);
- // 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)
- {
- 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];
- }
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidgetPrivate::setNodeValue(int index, double* nodeValues)
- {
- if (this->PiecewiseFunction->GetSize() <= index)
- {
- this->PiecewiseFunction->AddPoint(
- nodeValues[0], nodeValues[1], nodeValues[2], nodeValues[3]);
- }
- else
- {
- this->PiecewiseFunction->SetNodeValue(index, nodeValues);
- }
- }
- // ----------------------------------------------------------------------------
- // ctkVTKThresholdWidget methods
- // ----------------------------------------------------------------------------
- ctkVTKThresholdWidget::ctkVTKThresholdWidget(QWidget* parentWidget)
- :QWidget(parentWidget)
- , d_ptr(new ctkVTKThresholdWidgetPrivate(*this))
- {
- Q_D(ctkVTKThresholdWidget);
- d->setupUi(this);
- }
- // ----------------------------------------------------------------------------
- ctkVTKThresholdWidget::~ctkVTKThresholdWidget()
- {
- }
- // ----------------------------------------------------------------------------
- vtkPiecewiseFunction* ctkVTKThresholdWidget::piecewiseFunction()const
- {
- Q_D(const ctkVTKThresholdWidget);
- return d->PiecewiseFunction;
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidget
- ::setPiecewiseFunction(vtkPiecewiseFunction* newFunction)
- {
- Q_D(ctkVTKThresholdWidget);
- if (d->PiecewiseFunction == newFunction)
- {
- return;
- }
- this->qvtkReconnect(d->PiecewiseFunction, newFunction, vtkCommand::ModifiedEvent,
- this, SLOT(updateFromPiecewiseFunction()));
- d->PiecewiseFunction = newFunction;
-
- if (!d->UserRange)
- {
- double range[2] = {0., 1.};
- if (d->PiecewiseFunction)
- {
- d->PiecewiseFunction->GetRange(range);
- }
- d->setRange(range[0], range[1]);
- }
- if (d->PiecewiseFunction)
- {
- double min, max, value;
- d->guessThreshold(min, max, value);
- d->setThreshold(min, max, value);
- }
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidget::updateFromPiecewiseFunction()
- {
- Q_D(ctkVTKThresholdWidget);
-
- if (!d->PiecewiseFunction)
- {
- return;
- }
- double range[2];
- d->ThresholdSliderWidget->range(range);
- double minThreshold = range[0];
- double maxThreshold = range[1];
- double opacity = d->OpacitySliderWidget->value();
- double node[4];
- if (d->PiecewiseFunction->GetSize() > 1)
- {
- d->PiecewiseFunction->GetNodeValue(1, node);
- minThreshold = node[0];
- }
- if (d->PiecewiseFunction->GetSize() > 2)
- {
- d->PiecewiseFunction->GetNodeValue(2, node);
- 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);
- d->OpacitySliderWidget->blockSignals(true);
- d->OpacitySliderWidget->setValue(opacity);
- d->OpacitySliderWidget->blockSignals(wasBlocking);
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidget::setThresholdValues(double min, double max)
- {
- Q_D(ctkVTKThresholdWidget);
- d->setThreshold(min, max, d->OpacitySliderWidget->value());
- }
- // ----------------------------------------------------------------------------
- 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);
- d->setThreshold(d->ThresholdSliderWidget->minimumValue(),
- d->ThresholdSliderWidget->maximumValue(), opacity);
- }
- // ----------------------------------------------------------------------------
- double ctkVTKThresholdWidget::opacity()const
- {
- Q_D(const ctkVTKThresholdWidget);
- return d->OpacitySliderWidget->value();
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidget::range(double* range)const
- {
- Q_D(const ctkVTKThresholdWidget);
- d->ThresholdSliderWidget->range(range);
- }
- // ----------------------------------------------------------------------------
- void ctkVTKThresholdWidget::setRange(double min, double max)
- {
- Q_D(ctkVTKThresholdWidget);
- d->UserRange = true;
- d->setRange(min, max);
- }
|