| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 | /*=========================================================================  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 <QColor>#include <QDebug>/// CTK includes#include "ctkVTKCompositeFunction.h"/// VTK includes#include <vtkPiecewiseFunction.h>#include <vtkColorTransferFunction.h>#include <vtkSmartPointer.h>class ctkVTKCompositeFunctionPrivate{public:  vtkSmartPointer<vtkPiecewiseFunction>     PiecewiseFunction;  vtkSmartPointer<vtkColorTransferFunction> ColorTransferFunction;};//-----------------------------------------------------------------------------ctkVTKCompositeFunction::ctkVTKCompositeFunction(vtkPiecewiseFunction* piecewiseFunction,                                                 vtkColorTransferFunction* colorTransferFunction,                                                 QObject* parentObject)  :ctkTransferFunction(parentObject)  , d_ptr(new ctkVTKCompositeFunctionPrivate){  this->setPiecewiseFunction(piecewiseFunction);  this->setColorTransferFunction(colorTransferFunction);}//-----------------------------------------------------------------------------ctkVTKCompositeFunction::~ctkVTKCompositeFunction(){}//-----------------------------------------------------------------------------int ctkVTKCompositeFunction::count()const{  Q_D(const ctkVTKCompositeFunction);  // count points from piecewise  // could be from color transfer function  if (d->PiecewiseFunction.GetPointer() == 0)    {    Q_ASSERT(d->PiecewiseFunction.GetPointer());    return -1;    }  if (d->ColorTransferFunction.GetPointer() == 0)    {    Q_ASSERT(d->ColorTransferFunction.GetPointer());    return -1;    }  //qDebug() << "Piecewise: " << d->PiecewiseFunction->GetSize();  //qDebug() << "Color Transfer: " << d->ColorTransferFunction->GetSize();  // check if 2 tranfer function have same size  Q_ASSERT( d->PiecewiseFunction->GetSize() == d->ColorTransferFunction->GetSize());  return d->PiecewiseFunction->GetSize();}//-----------------------------------------------------------------------------bool ctkVTKCompositeFunction::isDiscrete()const{  return false;}//-----------------------------------------------------------------------------bool ctkVTKCompositeFunction::isEditable()const{  return true;}//-----------------------------------------------------------------------------void ctkVTKCompositeFunction::range(qreal& minRange, qreal& maxRange)const{  Q_D(const ctkVTKCompositeFunction);  if (d->PiecewiseFunction.GetPointer() == 0)    {    Q_ASSERT(d->PiecewiseFunction.GetPointer());    minRange = 1.;    maxRange = 0.;    return;    }  double rangeValues[2];  d->PiecewiseFunction->GetRange(rangeValues);  minRange = rangeValues[0];  maxRange = rangeValues[1];}//-----------------------------------------------------------------------------QVariant ctkVTKCompositeFunction::minValue()const{  Q_D(const ctkVTKCompositeFunction);  if (d->PiecewiseFunction.GetPointer() == 0)    {    Q_ASSERT(d->PiecewiseFunction.GetPointer());    return -1;    }  //Initialize to max value  double minValue = VTK_DOUBLE_MAX;  for (int i = 0; i < this->count(); ++i)    {    double value[4];    d->PiecewiseFunction->GetNodeValue(i, value);    minValue = qMin(value[1], minValue);    }  return minValue;}//-----------------------------------------------------------------------------QVariant ctkVTKCompositeFunction::maxValue()const{  Q_D(const ctkVTKCompositeFunction);  if (d->PiecewiseFunction.GetPointer() == 0)    {    Q_ASSERT(d->PiecewiseFunction.GetPointer());    return -1;    }  //Initialize to min value  double maxValue = VTK_DOUBLE_MIN;  for (int i = 0; i < this->count(); ++i)    {    double value[4];    d->PiecewiseFunction->GetNodeValue(i, value);    maxValue = qMax(maxValue, value[1]);    }  return maxValue;}//-----------------------------------------------------------------------------ctkControlPoint* ctkVTKCompositeFunction::controlPoint(int index)const{  Q_D(const ctkVTKCompositeFunction);  Q_ASSERT(index >= 0 && index < this->count());  double valuesPWF[4];  double valuesCTF[6];#ifndef QT_NO_DEBUG  double* rangePWF = d->PiecewiseFunction->GetRange();  double* rangeCTF = d->ColorTransferFunction->GetRange();#endif  d->PiecewiseFunction->GetNodeValue(index, valuesPWF);  d->ColorTransferFunction->GetNodeValue(index, valuesCTF);  QVariant rangeY[2];  rangeY[0] = this->minValue();  rangeY[1] = this->maxValue();  // test piecewise  Q_ASSERT(valuesPWF[0] >= rangePWF[0] && valuesPWF[0] <= rangePWF [1] &&  // X    valuesPWF[1] >= rangeY[0].toDouble() && valuesPWF[1] <= rangeY[1].toDouble()  &&  // Y    valuesPWF[2] >= 0. && valuesPWF[2] <= 1. &&                // Midpoint    valuesPWF[3] >= 0. && valuesPWF[3] <= 1. );                // Sharpness  // test color transfer  Q_ASSERT(valuesCTF[0] >= rangeCTF[0] &&    valuesCTF[0] <= rangeCTF[1] &&    valuesCTF[1] >= 0. && valuesCTF[1] <= 1. &&  // Red    valuesCTF[2] >= 0. && valuesCTF[2] <= 1. &&  // Green    valuesCTF[3] >= 0. && valuesCTF[3] <= 1. &&  // Blue    valuesCTF[4] >= 0. && valuesCTF[4] <= 1. &&  // MidPoint    valuesCTF[5] >= 0. && valuesCTF[5] <= 1.);   // Sharpness  // if only 2 points -> linear  if (index + 1 >= this->count())    {    ctkControlPoint* cp = new ctkControlPoint();    cp->P.X = valuesPWF[0];    // update value of QVariant    cp->P.Value = QColor::fromRgbF(      valuesCTF[1], valuesCTF[2], valuesCTF[3], valuesPWF[1]);    return cp;    }  //else  ctkNonLinearControlPoint* cp = new ctkNonLinearControlPoint();  cp->P.X = valuesPWF[0];  // update value of QVariant  cp->P.Value = QColor::fromRgbF(valuesCTF[1], valuesCTF[2], valuesCTF[3], valuesPWF[1]);  double nextValuesPWF[4], nextValuesCTF[6];  d->PiecewiseFunction->GetNodeValue(index + 1, nextValuesPWF);  d->ColorTransferFunction->GetNodeValue(index + 1, nextValuesCTF);  Q_ASSERT(nextValuesPWF[0] >= rangePWF[0] && nextValuesPWF[0] <= rangePWF[1]  &&  // X    nextValuesPWF[1] >= rangeY[0].toDouble() && nextValuesPWF[1] <= rangeY[1].toDouble()  &&  // Y    nextValuesPWF[2] >= 0. && nextValuesPWF[2] <= 1. &&                // Midpoint    nextValuesPWF[3] >= 0. && nextValuesPWF[3] <= 1. );                // Sharpness  Q_ASSERT(nextValuesCTF[0] >= rangeCTF[0] &&    nextValuesCTF[0] <= rangeCTF[1] &&    nextValuesCTF[1] >= 0. && nextValuesCTF[1] <= 1. &&  // Red    nextValuesCTF[2] >= 0. && nextValuesCTF[2] <= 1. &&  // Green    nextValuesCTF[3] >= 0. && nextValuesCTF[3] <= 1. &&  // Blue    nextValuesCTF[4] >= 0. && nextValuesCTF[4] <= 1. &&  // MidPoint    nextValuesCTF[5] >= 0. && nextValuesCTF[5] <= 1.);   // Sharpness  // Optimization: don't use subPoints if the ramp is linear (sharpness == 0)  if (valuesPWF[3] == 0. && valuesCTF[5] == 0.)    {    cp->SubPoints << ctkPoint(valuesPWF[0], QColor::fromRgbF(      valuesCTF[1], valuesCTF[2], valuesCTF[3], valuesPWF[1]));    cp->SubPoints << ctkPoint(nextValuesPWF[0], QColor::fromRgbF(      nextValuesCTF[1], nextValuesCTF[2], nextValuesCTF[3], nextValuesPWF[1]));    return cp;    }  double subPointsCTF[300];  double subPointsPWF[100];  d->ColorTransferFunction->GetTable(cp->x(), nextValuesCTF[0], 100, subPointsCTF);  d->PiecewiseFunction->GetTable(cp->x(), nextValuesCTF[0], 100, subPointsPWF);  qreal interval = (nextValuesCTF[0] - cp->x()) / 99.;  for(int i = 0; i < 100; ++i)    {    qreal red =  subPointsCTF[3*i];    qreal green =  subPointsCTF[3*i+1];    qreal blue =  subPointsCTF[3*i+2];    qreal alpha = subPointsPWF[i];    QColor compositeValue = QColor::fromRgbF(red, green, blue, alpha );    cp->SubPoints << ctkPoint(cp->x() + interval*i, compositeValue);    }  return cp;}//-----------------------------------------------------------------------------QVariant ctkVTKCompositeFunction::value(qreal pos)const{  Q_D(const ctkVTKCompositeFunction);  Q_ASSERT(d->PiecewiseFunction.GetPointer());  Q_ASSERT(d->ColorTransferFunction.GetPointer());  // Get color  double rgb[3];  d->ColorTransferFunction->GetColor(pos, rgb);  // Get Alpha  qreal alpha;  alpha = d->PiecewiseFunction->GetValue( pos );  // returns RGBA  QColor compositeValue(rgb[0], rgb[1], rgb[2], alpha);  return compositeValue;}//-----------------------------------------------------------------------------int ctkVTKCompositeFunction::insertControlPoint(const ctkControlPoint& cp){  Q_UNUSED(cp);  Q_D(ctkVTKCompositeFunction);  int index = -1;  // check piecewise  if (d->PiecewiseFunction.GetPointer() == 0)    {    return index;    }  // cp: x  // value = rgba  /*  // check color tf  qreal value = cp.value().value<qreal>();  const ctkNonLinearControlPoint* nonLinearCp = dynamic_cast<const ctkNonLinearControlPoint*>(&cp);  if (nonLinearCp)    {    // TODO retrieve midpoint & sharpness    index = d->PiecewiseFunction->AddPoint(      cp.x(), value);    }  else    {    index = d->PiecewiseFunction->AddPoint(      cp.x(), value);    }*/  return index;}//-----------------------------------------------------------------------------int ctkVTKCompositeFunction::insertControlPoint(qreal pos){  Q_D(ctkVTKCompositeFunction);  int index = -1;  // check piecewise  if (d->PiecewiseFunction.GetPointer() == 0)    {    return index;    }  //check color tf  if (d->ColorTransferFunction.GetPointer() == 0)    {    return index;    }  // Add color to CTF  double color[3];  d->ColorTransferFunction->GetColor( pos, color );  int indexColor =      d->ColorTransferFunction->AddRGBPoint( pos, color[0], color[1], color[2] );  // Add point to piecewise#ifndef QT_NO_DEBUG  int indexPiecewise =#endif      d->PiecewiseFunction->AddPoint( pos, 0);  // check index  Q_ASSERT(indexColor == indexPiecewise);  index = indexColor;  return index;}//-----------------------------------------------------------------------------void ctkVTKCompositeFunction::setControlPointPos(int index, qreal pos){  Q_D(ctkVTKCompositeFunction);  // update X pos in the CTF  double valuesColor[6];  d->ColorTransferFunction->GetNodeValue(index, valuesColor);  valuesColor[0] = pos;  // warning, a possible new range is not supported  // SetNodeValue eventually fire the signal changed()  d->ColorTransferFunction->SetNodeValue(index, valuesColor);  // Update X pos in the PWF  double valuesPiecewise[4];  d->PiecewiseFunction->GetNodeValue(index, valuesPiecewise);  // warning, a possible new range is not supported  // SetNodeValue eventually fire the signal changed()  valuesPiecewise[0] = pos;  d->PiecewiseFunction->SetNodeValue(index, valuesPiecewise);}//-----------------------------------------------------------------------------void ctkVTKCompositeFunction::setControlPointValue(int index, const QVariant& value){  Q_D(ctkVTKCompositeFunction);  // QVariant = RGBA  double values[4];  d->PiecewiseFunction->GetNodeValue(index, values);  values[1] = value.toDouble();  // setNodeValue should eventually fired the signal changed()  d->PiecewiseFunction->SetNodeValue(index, values);}//-----------------------------------------------------------------------------void ctkVTKCompositeFunction::setPiecewiseFunction(vtkPiecewiseFunction* piecewiseFunction){  Q_D(ctkVTKCompositeFunction);  d->PiecewiseFunction = piecewiseFunction;  this->qvtkReconnect(d->PiecewiseFunction,vtkCommand::ModifiedEvent,                      this, SIGNAL(changed()));  emit changed();}//-----------------------------------------------------------------------------void ctkVTKCompositeFunction::setColorTransferFunction(vtkColorTransferFunction* colorTransferFunction){  Q_D(ctkVTKCompositeFunction);  d->ColorTransferFunction = colorTransferFunction;  this->qvtkReconnect(d->ColorTransferFunction,vtkCommand::ModifiedEvent,                      this, SIGNAL(changed()));  emit changed();}//-----------------------------------------------------------------------------vtkPiecewiseFunction* ctkVTKCompositeFunction::piecewiseFunction()const{  Q_D(const ctkVTKCompositeFunction);  return d->PiecewiseFunction;}//-----------------------------------------------------------------------------vtkColorTransferFunction* ctkVTKCompositeFunction::colorTransferFunction()const{  Q_D(const ctkVTKCompositeFunction);  return d->ColorTransferFunction;}//-----------------------------------------------------------------------------void ctkVTKCompositeFunction::removeControlPoint( qreal pos ){  Q_UNUSED(pos);  // TO BE IMPLEMENTED}
 |