Browse Source

ENH: Move the computation of gradient from ctkTransferFunctionGradientItem into ctkTransferFunctionScene

Julien Finet 15 years ago
parent
commit
8c195914c1

+ 5 - 99
Libs/Widgets/ctkTransferFunctionGradientItem.cpp

@@ -30,6 +30,7 @@
 /// CTK includes
 #include "ctkTransferFunction.h"
 #include "ctkTransferFunctionGradientItem.h"
+#include "ctkTransferFunctionScene.h"
 
 //-----------------------------------------------------------------------------
 ctkTransferFunctionGradientItem::ctkTransferFunctionGradientItem(QGraphicsItem* parentGraphicsItem)
@@ -53,105 +54,10 @@ ctkTransferFunctionGradientItem::~ctkTransferFunctionGradientItem()
 void ctkTransferFunctionGradientItem::paint(
   QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
 {
-  int count = this->transferFunction() ? this->transferFunction()->count() : 0;
-  if (count <= 0)
-    {
-    painter->fillRect(this->rect(),Qt::black);
-    return;
-    }
-  qreal range[2];
-  this->transferFunction()->range(range);
-  qreal rangeDiff = this->rect().width() / (range[1] - range[0]);
-  qreal rangeOffset = range[0];
-  ctkControlPoint* startCP = this->transferFunction()->controlPoint(0);
-  ctkControlPoint* endCP = 0;
+  ctkTransferFunctionScene* tfScene = dynamic_cast<ctkTransferFunctionScene*>(this->scene());
+  Q_ASSERT(tfScene);
   
-  qreal start = (startCP->x() - rangeOffset) * rangeDiff;
-  qreal end = 0;
-  for(int i = 1; i < count; ++i)
-    {
-    endCP = this->transferFunction()->controlPoint(i);
-    // TODO, handle Bezier points for a finer gradient
-    // TODO, handle nonlinear points
-    if (this->transferFunction()->isDiscrete())
-      {
-      // pos
-      end = ((startCP->x() + endCP->x()) /2. -rangeOffset) * rangeDiff;
-      QRectF itemRect = QRectF(start, 0, end - start, 
-                               this->rect().height());
-      if (i==1)
-        {
-        itemRect.setLeft(0.);
-        }
-      QColor valueColor = this->color(startCP->value());
-      // paint
-      painter->fillRect(itemRect, valueColor);
-      // draw the last item
-      if (i == count -1)
-        {
-        //pos
-        itemRect = QRectF(end, 0, this->rect().width(), 
-                          this->rect().height());
-        // color
-        valueColor = this->color(endCP->value());
-        // paint
-        painter->fillRect(itemRect, valueColor);
-        }
-      }
-    else if (dynamic_cast<ctkNonLinearControlPoint*>(startCP) != 0)
-      {
-      QList<ctkPoint> points = this->nonLinearPoints(startCP, endCP);
-      for (int j = 1; j < points.count(); ++j)
-        {
-        // pos
-        end = (points[j].X - rangeOffset) * rangeDiff;
-        QRectF itemRect = QRectF(start, 0, end - start, 
-                                 this->rect().height());
-        if (i==1 && j == 1)
-          {
-          itemRect.setLeft(0.);
-          }
-        if ((i == count -1) && (j == points.count() -1))
-          {
-          itemRect.setRight(this->rect().width());
-          }
-        // color
-        QLinearGradient gradient(start, 0, end, 0);
-        gradient.setColorAt(0, this->color(points[j-1]));
-        gradient.setColorAt(1, this->color(points[j]));
-        // paint
-        painter->fillRect(itemRect, gradient);
-        start = end;
-        }
-      }
-    else
-      {
-      // pos
-      end = (endCP->x() - rangeOffset) * rangeDiff;
-      QRectF itemRect = QRectF(start, 0, end - start, 
-                               this->rect().height());
-      if (i==1)
-        {
-        itemRect.setLeft(0.);
-        }
-      if (i == count -1)
-        {
-        itemRect.setRight(this->rect().width());
-        }
-      // color
-      QLinearGradient gradient(start, 0, end, 0);
-      gradient.setColorAt(0, this->color(startCP->value()));
-      gradient.setColorAt(1, this->color(endCP->value()));
-      // paint
-      painter->fillRect(itemRect, gradient);
-      }
-    delete startCP;
-    startCP = endCP;
-    start = end;
-    }
-  if (startCP)
-    {
-    delete startCP;
-    }
+  const QGradient& gradient = tfScene->gradient();
+  painter->fillRect(this->rect(), gradient);
 }
 

+ 93 - 14
Libs/Widgets/ctkTransferFunctionScene.cpp

@@ -19,6 +19,7 @@
 =========================================================================*/
 /// Qt includes
 #include <QGraphicsScene>
+#include <QLinearGradient>
 #include <QResizeEvent>
 #include <QDebug>
 
@@ -26,6 +27,9 @@
 #include "ctkTransferFunction.h"
 #include "ctkTransferFunctionScene.h"
 
+/// STL includes
+#include <limits>
+
 //-----------------------------------------------------------------------------
 class ctkTransferFunctionScenePrivate: public ctkPrivate<ctkTransferFunctionScene>
 {
@@ -35,6 +39,7 @@ public:
   QRectF               OldRect;
   ctkTransferFunction* TransferFunction;
   QPainterPath   Path;
+  QLinearGradient Gradient;
   QList<QPointF> Points;
   qreal        WorldRangeX[2];
   QVariant     WorldRangeY[2];
@@ -106,6 +111,7 @@ const QPainterPath& ctkTransferFunctionScene::curve()const
   if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
     {
     const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    const_cast<ctkTransferFunctionScene*>(this)->computeGradient();
     }
   return d->Path;
 }
@@ -117,11 +123,24 @@ const QList<QPointF>& ctkTransferFunctionScene::points()const
   if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
     {
     const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    const_cast<ctkTransferFunctionScene*>(this)->computeGradient();
     }
   return d->Points;
 }
 
 //-----------------------------------------------------------------------------
+const QGradient& ctkTransferFunctionScene::gradient()const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
+    {
+    const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    const_cast<ctkTransferFunctionScene*>(this)->computeGradient();
+    }
+  return d->Gradient;
+}
+
+//-----------------------------------------------------------------------------
 void ctkTransferFunctionScene::computeCurve()
 {
   CTK_D(ctkTransferFunctionScene);
@@ -133,8 +152,8 @@ void ctkTransferFunctionScene::computeCurve()
     }
   qDebug() << "computeCurve" << this->sceneRect();
   d->TransferFunction->range(d->WorldRangeX[0], d->WorldRangeX[1]);
-  d->WorldRangeY[0] = this->y(d->TransferFunction->minValue());
-  d->WorldRangeY[1] = this->y(d->TransferFunction->maxValue());
+  d->WorldRangeY[0] = this->posY(d->TransferFunction->minValue());
+  d->WorldRangeY[1] = this->posY(d->TransferFunction->maxValue());
 
   d->RangeXDiff   = this->computeRangeXDiff(this->sceneRect(), d->WorldRangeX);
   d->RangeXOffSet = this->computeRangeXOffset(d->WorldRangeX);
@@ -189,6 +208,78 @@ void ctkTransferFunctionScene::computeCurve()
 }
 
 //-----------------------------------------------------------------------------
+void ctkTransferFunctionScene::computeGradient()
+{
+  CTK_D(ctkTransferFunctionScene);
+
+  int count = d->TransferFunction ? d->TransferFunction->count() : 0;
+  if (count <= 0)
+    {
+    return;
+    }
+  qDebug() << "computeCurve" << this->sceneRect();
+  d->TransferFunction->range(d->WorldRangeX[0], d->WorldRangeX[1]);
+  d->WorldRangeY[0] = this->posY(d->TransferFunction->minValue());
+  d->WorldRangeY[1] = this->posY(d->TransferFunction->maxValue());
+
+  d->RangeXDiff   = this->computeRangeXDiff(QRectF(0.,0.,1.,1.), d->WorldRangeX);
+  d->RangeXOffSet = this->computeRangeXOffset(d->WorldRangeX);
+
+  d->RangeYDiff   = this->computeRangeYDiff(QRectF(0.,0.,1.,1.), d->WorldRangeY);
+  d->RangeYOffSet = this->computeRangeYOffset(d->WorldRangeY);
+
+  ctkControlPoint* startCP = d->TransferFunction->controlPoint(0);
+  ctkControlPoint* nextCP = 0;
+
+  qreal startPos = this->mapXToScreen(this->posX(startCP->x()));
+  qreal nextPos;
+  
+  d->Gradient = QLinearGradient(0., 0., 1., 0.);
+  d->Gradient.setColorAt(startPos, this->color(startCP));
+
+  for(int i = 1; i < count; ++i)
+    {
+    nextCP = d->TransferFunction->controlPoint(i);
+    nextPos = this->mapXToScreen(this->posX(nextCP));
+    if (this->transferFunction()->isDiscrete())
+      {
+      qreal midPoint = (startPos + nextPos)  / 2;
+      d->Gradient.setColorAt(midPoint, this->color(startCP));
+      d->Gradient.setColorAt(midPoint + std::numeric_limits<qreal>::epsilon(), this->color(nextCP));
+      }
+    else if (dynamic_cast<ctkNonLinearControlPoint*>(startCP))
+      {
+      QList<ctkPoint> points = this->nonLinearPoints(startCP, nextCP);
+      foreach(const ctkPoint& p, points)
+        {
+        d->Gradient.setColorAt(this->mapXToScreen(this->posX(p)), this->color(p));
+        }
+      //no need, d->Gradient.setColorAt(nextPos, this->color(nextCP));
+      }
+    else //dynamic_cast<ctkBezierControlPoint*>(startCP))
+      { // TODO handle bezier points with color
+      QList<ctkPoint> points = this->bezierParams(startCP, nextCP);
+      QList<ctkPoint>::iterator it = points.begin();
+      QList<QPointF> bezierPoints;
+      foreach(const ctkPoint& p, points)
+        {
+        d->Gradient.setColorAt(this->mapXToScreen(this->posX(p)), this->color(p));
+        }
+      nextPos = this->mapXToScreen(this->posX(points[points.size() - 1])); 
+      }
+    //qDebug() << i << points[0] << points[1] << points[2] << points[3];
+    delete startCP;
+    startCP = nextCP;
+    startPos = nextPos;
+    }
+  d->Gradient.setColorAt(startPos, this->color(startCP));
+  if (startCP)
+    {
+    delete startCP;
+    }
+}
+
+//-----------------------------------------------------------------------------
 QList<ctkPoint> ctkTransferFunctionScene::bezierParams(
   ctkControlPoint* start, ctkControlPoint* end) const
 {
@@ -231,18 +322,6 @@ QList<ctkPoint> ctkTransferFunctionScene::nonLinearPoints(
   return nonLinearCP->SubPoints;
 }
 
-
-//-----------------------------------------------------------------------------
-qreal ctkTransferFunctionScene::y(const QVariant& v) const
-{ 
-  Q_ASSERT(v.canConvert<qreal>() || v.canConvert<QColor>());
-  if (v.canConvert<QColor>())
-    {
-    return v.value<QColor>().alphaF();
-    }
-  return v.toReal();
-}
-
 //-----------------------------------------------------------------------------
 QColor ctkTransferFunctionScene::color(const QVariant& v) const
 { 

+ 44 - 8
Libs/Widgets/ctkTransferFunctionScene.h

@@ -25,13 +25,14 @@
 #include <QGraphicsScene>
 
 /// CTK includes
-#include "CTKWidgetsExport.h"
 #include "ctkPimpl.h"
+#include "ctkTransferFunction.h"
+#include "CTKWidgetsExport.h"
 
-class ctkTransferFunction;
+//class ctkTransferFunction;
 class ctkTransferFunctionScenePrivate;
-class ctkControlPoint;
-class ctkPoint;
+//class ctkControlPoint;
+//class ctkPoint;
 
 //-----------------------------------------------------------------------------
 class CTK_WIDGETS_EXPORT ctkTransferFunctionScene: public QGraphicsScene
@@ -45,11 +46,17 @@ public:
   void setTransferFunction(ctkTransferFunction* transferFunction);
   ctkTransferFunction* transferFunction()const;
 
-  qreal y(const QVariant& v) const;
-  QColor color(const QVariant& v) const;
+  inline qreal posX(const ctkControlPoint* cp)const;
+  inline qreal posY(const ctkControlPoint* cp)const;
+  inline QColor color(const ctkControlPoint* cp) const;
+
+  inline qreal posX(const ctkPoint& point)const;
+  inline qreal posY(const ctkPoint& point)const;
+  inline QColor color(const ctkPoint& point) const;
 
-  qreal posX(const qreal& x)const;
-  qreal posY(const QVariant& value)const;
+  qreal posX(const qreal& tfX)const;
+  qreal posY(const QVariant& tfV)const;
+  QColor color(const QVariant& tfV) const;
   
   QPointF mapPointToScreen(const ctkControlPoint* cp)const;
   QPointF mapPointToScreen(const ctkPoint& point)const;
@@ -64,7 +71,10 @@ public:
 
   const QPainterPath& curve()const;
   const QList<QPointF>& points()const;
+  const QGradient& gradient()const;
+
   void computeCurve();
+  void computeGradient();
 
 protected slots:
   virtual void onTransferFunctionChanged();
@@ -78,4 +88,30 @@ private:
   CTK_DECLARE_PRIVATE(ctkTransferFunctionScene);
 };
 
+qreal ctkTransferFunctionScene::posX(const ctkControlPoint* cp)const
+{
+  return this->posX(cp->x());
+}
+qreal ctkTransferFunctionScene::posY(const ctkControlPoint* cp)const
+{
+  return this->posY(cp->value());
+}
+QColor ctkTransferFunctionScene::color(const ctkControlPoint* cp) const
+{
+  return this->color(cp->value());
+}
+
+qreal ctkTransferFunctionScene::posX(const ctkPoint& point)const
+{
+  return this->posX(point.X);
+}
+qreal ctkTransferFunctionScene::posY(const ctkPoint& point)const
+{
+  return this->posY(point.Value);
+}
+QColor ctkTransferFunctionScene::color(const ctkPoint& point) const
+{
+  return this->color(point.Value);
+}
+
 #endif