Quellcode durchsuchen

ENH: Move ctkTransferFunction path computation into ctkTransferFunctionScene + Scale the qgraphicsscene instead of resizing the objects.
The computation can be expensive, it should be ideally done only once for all the qgraphicsitem in the scene. This is why we move it into ctkTransferFunctionScene.
By setting a scaling coefficient into the scene, the transfer function path/curve doesn't depend on the size of the view anymore. All the items are between 0 and 1.

Julien Finet vor 15 Jahren
Ursprung
Commit
f4f776ab29

+ 3 - 0
Libs/Widgets/CMakeLists.txt

@@ -64,6 +64,8 @@ SET(KIT_SRCS
   ctkTransferFunctionItem.h
   ctkTransferFunctionWidget.cpp
   ctkTransferFunctionWidget.h
+  ctkTransferFunctionScene.cpp
+  ctkTransferFunctionScene.h
   ctkTreeComboBox.cpp
   ctkTreeComboBox.h
   )
@@ -97,6 +99,7 @@ SET(KIT_MOC_SRCS
   ctkTransferFunctionItem.h
   ctkTransferFunctionControlPointsItem.h
   ctkTransferFunctionWidget.h
+  ctkTransferFunctionScene.h
   ctkTreeComboBox.h
   )
 

+ 11 - 66
Libs/Widgets/ctkTransferFunctionControlPointsItem.cpp

@@ -28,8 +28,8 @@
 #include <QVariant>
 
 /// CTK includes
-#include "ctkTransferFunction.h"
 #include "ctkTransferFunctionControlPointsItem.h"
+#include "ctkTransferFunctionScene.h"
 
 //-----------------------------------------------------------------------------
 class ctkTransferFunctionControlPointsItemPrivate: 
@@ -46,7 +46,7 @@ public:
 //-----------------------------------------------------------------------------
 ctkTransferFunctionControlPointsItemPrivate::ctkTransferFunctionControlPointsItemPrivate()
 {
-  this->PointSize = QSizeF(10.,10.);
+  this->PointSize = QSizeF(0.01,0.01);
   this->SelectedPoint = -1;
 }
 
@@ -90,74 +90,19 @@ void ctkTransferFunctionControlPointsItem::paint(
     return;
     }
 
-  qreal rangeXDiff = this->rangeXDiff();
-  qreal rangeXOffSet = this->rangeXOffSet();
-
-  qreal rangeYDiff = this->rangeYDiff();
-  qreal rangeYOffSet = this->rangeYDiff();
-
-  ctkControlPoint* startCP = this->transferFunction()->controlPoint(0);
-  ctkControlPoint* endCP = 0;
-  qreal start = 0;
-  qreal end = 0;
-
-  QPainterPath path;
- // this->x(controlpoint)
-  QPointF startPos(startCP->x() - rangeXOffSet, this->y(startCP->value()) - rangeYOffSet);
-  startPos.rx() *= rangeXDiff;
-  startPos.setY(this->rect().height() 
-                - startPos.y() * rangeYDiff);
+  ctkTransferFunctionScene* tfScene = dynamic_cast<ctkTransferFunctionScene*>(this->scene());
+  Q_ASSERT(tfScene);
   
-  d->ControlPoints.clear();
-  d->ControlPoints << startPos;
-
-  path.moveTo(startPos);
-  for(int i = 1; i < count; ++i)
-    {
-    endCP = this->transferFunction()->controlPoint(i);
-    if (dynamic_cast<ctkNonLinearControlPoint*>(startCP))
-      {
-      QList<ctkPoint> points = this->nonLinearPoints(startCP, endCP);
-      int j;
-      for (j = 1; j < points.count(); ++j)
-        {
-        path.lineTo(
-          QPointF(
-            this->transferFunction2ScreenCoordinates(points[j].X,
-                                                     this->y(points[j].Value))));
-        }
-      j = points.count() - 1;
-      d->ControlPoints << QPointF( this->transferFunction2ScreenCoordinates(
-        points[j].X,
-        this->y(points[j].Value)));
-      }
-    else //dynamic_cast<ctkBezierControlPoint*>(startCP))
-      {
-      QList<ctkPoint> points = this->bezierParams(startCP, endCP);
-      QList<ctkPoint>::iterator it = points.begin();
-      QList<QPointF> bezierPoints;
-      foreach(const ctkPoint& p, points)
-        {
-        bezierPoints << 
-          QPointF((p.X - rangeXOffSet)* rangeXDiff , 
-                  this->rect().height() - (this->y(p.Value) - rangeYOffSet)* rangeYDiff);
-        }
-      path.cubicTo(bezierPoints[1], bezierPoints[2], bezierPoints[3]);
-      d->ControlPoints << bezierPoints[3];
-      }
-    //qDebug() << i << points[0] << points[1] << points[2] << points[3];
-    delete startCP;
-    startCP = endCP;
-    }
-  if (startCP)
-    {
-    delete startCP;
-    }
+  const QPainterPath& curve = tfScene->curve();
   painter->setRenderHint(QPainter::Antialiasing);
-  painter->setPen(QPen(QColor(255, 255, 255, 191), 1));
-  painter->drawPath(path);
+  QPen pen(QColor(255, 255, 255, 191), 1);
+  pen.setCosmetic(true);
+  painter->setPen(pen);
+  painter->drawPath(curve);
 
+  d->ControlPoints = tfScene->points();
   QPainterPath points;
+  points.setFillRule(Qt::WindingFill);
   foreach(const QPointF& point, d->ControlPoints)
     {
     points.addEllipse(point, d->PointSize.width(), d->PointSize.height());

+ 10 - 14
Libs/Widgets/ctkTransferFunctionItem.cpp

@@ -37,7 +37,7 @@ class ctkTransferFunctionItemPrivate :
 {
 public:
   ctkTransferFunctionItemPrivate();
-
+  void init();
   QRectF               Rect;
   ctkTransferFunction* TransferFunction;
 };
@@ -46,6 +46,13 @@ public:
 ctkTransferFunctionItemPrivate::ctkTransferFunctionItemPrivate()
 {
   this->TransferFunction = 0;
+  this->Rect = QRectF(0.,0.,1.,1.);
+}
+
+//-----------------------------------------------------------------------------
+void ctkTransferFunctionItemPrivate::init()
+{
+  CTK_P(ctkTransferFunctionItem);
 }
 
 //-----------------------------------------------------------------------------
@@ -53,6 +60,7 @@ ctkTransferFunctionItem::ctkTransferFunctionItem(QGraphicsItem* parentGraphicsIt
   :QGraphicsObject(parentGraphicsItem)
 {
   CTK_INIT_PRIVATE(ctkTransferFunctionItem);
+  ctk_d()->init();
 }
 
 //-----------------------------------------------------------------------------
@@ -61,6 +69,7 @@ ctkTransferFunctionItem::ctkTransferFunctionItem(
   :QGraphicsObject(parentItem)
 {
   CTK_INIT_PRIVATE(ctkTransferFunctionItem);
+  ctk_d()->init();
   this->setTransferFunction(transferFunction);
 }
 
@@ -74,14 +83,7 @@ ctkTransferFunctionItem::~ctkTransferFunctionItem()
 void ctkTransferFunctionItem::setTransferFunction(ctkTransferFunction* transferFunction)
 {
   CTK_D(ctkTransferFunctionItem);
-  if (d->TransferFunction == transferFunction)
-    {
-    return;
-    }
   d->TransferFunction = transferFunction;
-  connect(d->TransferFunction, SIGNAL(changed()),
-          this, SLOT(onTransferFunctionChanged()));
-  this->update();
 }
 
 //-----------------------------------------------------------------------------
@@ -92,12 +94,6 @@ ctkTransferFunction* ctkTransferFunctionItem::transferFunction() const
 }
 
 //-----------------------------------------------------------------------------
-void ctkTransferFunctionItem::onTransferFunctionChanged()
-{
-  this->update();
-}
-
-//-----------------------------------------------------------------------------
 void ctkTransferFunctionItem::setRect(const QRectF& newRect)
 {
   CTK_D(ctkTransferFunctionItem);

+ 1 - 2
Libs/Widgets/ctkTransferFunctionItem.h

@@ -69,8 +69,7 @@ protected:
 
   QList<ctkPoint> bezierParams(ctkControlPoint* start, ctkControlPoint* end)const;
   QList<ctkPoint> nonLinearPoints(ctkControlPoint* start, ctkControlPoint* end)const;
-protected slots:
-  virtual void onTransferFunctionChanged();
+
 private:
   CTK_DECLARE_PRIVATE(ctkTransferFunctionItem);
 };

+ 362 - 0
Libs/Widgets/ctkTransferFunctionScene.cpp

@@ -0,0 +1,362 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  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.commontk.org/LICENSE
+
+  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 <QGraphicsScene>
+#include <QResizeEvent>
+#include <QDebug>
+
+/// CTK includes
+#include "ctkTransferFunction.h"
+#include "ctkTransferFunctionScene.h"
+
+//-----------------------------------------------------------------------------
+class ctkTransferFunctionScenePrivate: public ctkPrivate<ctkTransferFunctionScene>
+{
+  CTK_DECLARE_PUBLIC(ctkTransferFunctionScene);
+public:
+  ctkTransferFunctionScenePrivate();
+  QRectF               OldRect;
+  ctkTransferFunction* TransferFunction;
+  QPainterPath   Path;
+  QList<QPointF> Points;
+  qreal        WorldRangeX[2];
+  QVariant     WorldRangeY[2];
+  qreal        RangeXDiff;
+  qreal        RangeXOffSet;
+  qreal        RangeYDiff;
+  qreal        RangeYOffSet;
+};
+
+ctkTransferFunctionScenePrivate::ctkTransferFunctionScenePrivate()
+{
+  this->TransferFunction = 0;
+}
+
+//-----------------------------------------------------------------------------
+ctkTransferFunctionScene::ctkTransferFunctionScene(QObject* parentObject)
+  :QGraphicsScene(parentObject)
+{
+  CTK_INIT_PRIVATE(ctkTransferFunctionScene);
+}
+
+//-----------------------------------------------------------------------------
+ctkTransferFunctionScene::ctkTransferFunctionScene(
+  ctkTransferFunction* transferFunction, QObject* parentObject)
+  :QGraphicsScene(parentObject)
+{
+  CTK_INIT_PRIVATE(ctkTransferFunctionScene);
+  this->setTransferFunction(transferFunction);
+}
+//-----------------------------------------------------------------------------
+ctkTransferFunctionScene::~ctkTransferFunctionScene()
+{
+}
+
+//-----------------------------------------------------------------------------
+void ctkTransferFunctionScene::setTransferFunction(ctkTransferFunction* transferFunction)
+{
+  CTK_D(ctkTransferFunctionScene);
+  if (d->TransferFunction == transferFunction)
+    {
+    return;
+    }
+  d->TransferFunction = transferFunction;
+  connect( d->TransferFunction, SIGNAL(changed()),
+           this, SLOT(onTransferFunctionChanged()),
+           Qt::UniqueConnection);
+  this->update();
+}
+
+//-----------------------------------------------------------------------------
+ctkTransferFunction* ctkTransferFunctionScene::transferFunction()const
+{
+  return ctk_d()->TransferFunction;
+}
+
+//-----------------------------------------------------------------------------
+void ctkTransferFunctionScene::onTransferFunctionChanged()
+{
+  CTK_D(ctkTransferFunctionScene);
+  // TODO delete cache here
+  d->Path = QPainterPath();
+  this->update();  
+}
+
+//-----------------------------------------------------------------------------
+const QPainterPath& ctkTransferFunctionScene::curve()const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
+    {
+    const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    }
+  return d->Path;
+}
+
+//-----------------------------------------------------------------------------
+const QList<QPointF>& ctkTransferFunctionScene::points()const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
+    {
+    const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    }
+  return d->Points;
+}
+
+//-----------------------------------------------------------------------------
+void ctkTransferFunctionScene::computeCurve()
+{
+  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->y(d->TransferFunction->minValue());
+  d->WorldRangeY[1] = this->y(d->TransferFunction->maxValue());
+
+  d->RangeXDiff   = this->computeRangeXDiff(this->sceneRect(), d->WorldRangeX);
+  d->RangeXOffSet = this->computeRangeXOffset(d->WorldRangeX);
+
+  d->RangeYDiff   = this->computeRangeYDiff(this->sceneRect(), d->WorldRangeY);
+  d->RangeYOffSet = this->computeRangeYOffset(d->WorldRangeY);
+
+  ctkControlPoint* startCP = d->TransferFunction->controlPoint(0);
+  ctkControlPoint* nextCP = 0;
+
+  QPointF startPos = this->mapPointToScreen(startCP);
+  
+  d->Points.clear();
+  d->Points << startPos;
+
+  d->Path = QPainterPath();
+  d->Path.moveTo(startPos);
+  for(int i = 1; i < count; ++i)
+    {
+    nextCP = d->TransferFunction->controlPoint(i);
+    if (dynamic_cast<ctkNonLinearControlPoint*>(startCP))
+      {
+      QList<ctkPoint> points = this->nonLinearPoints(startCP, nextCP);
+      int j;
+      for (j = 1; j < points.count(); ++j)
+        {
+        d->Path.lineTo(this->mapPointToScreen(points[j]));
+        }
+      j = points.count() - 1;
+      d->Points << this->mapPointToScreen(points[j]);
+      }
+    else //dynamic_cast<ctkBezierControlPoint*>(startCP))
+      {
+      QList<ctkPoint> points = this->bezierParams(startCP, nextCP);
+      QList<ctkPoint>::iterator it = points.begin();
+      QList<QPointF> bezierPoints;
+      foreach(const ctkPoint& p, points)
+        {
+        bezierPoints << this->mapPointToScreen(p);
+        }
+      d->Path.cubicTo(bezierPoints[1], bezierPoints[2], bezierPoints[3]);
+      d->Points << bezierPoints[3];
+      }
+    //qDebug() << i << points[0] << points[1] << points[2] << points[3];
+    delete startCP;
+    startCP = nextCP;
+    }
+  if (startCP)
+    {
+    delete startCP;
+    }
+}
+
+//-----------------------------------------------------------------------------
+QList<ctkPoint> ctkTransferFunctionScene::bezierParams(
+  ctkControlPoint* start, ctkControlPoint* end) const
+{
+  Q_ASSERT(start);
+  Q_ASSERT(end);
+  QList<ctkPoint> points; 
+  
+  ctkBezierControlPoint* bezierCP = dynamic_cast<ctkBezierControlPoint*>(start);
+  if (!bezierCP)
+    {// just duplicate start and end into p1 and p2
+    points << start->P;
+    points << start->P;
+    points << end->P;
+    points << end->P;
+    return points;
+    }
+  
+  points << start->P;
+  points << bezierCP->P1;
+  points << bezierCP->P2;
+  points << end->P;
+  return points;
+}
+
+//-----------------------------------------------------------------------------
+QList<ctkPoint> ctkTransferFunctionScene::nonLinearPoints(
+  ctkControlPoint* start, ctkControlPoint* end) const
+{
+  Q_ASSERT(start);
+    
+  ctkNonLinearControlPoint* nonLinearCP = 
+    dynamic_cast<ctkNonLinearControlPoint*>(start);
+  if (!nonLinearCP)
+    {
+    QList<ctkPoint> points; 
+    points << start->P;
+    points << end->P;
+    return points;
+    }
+  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
+{ 
+  //Q_ASSERT(v.canConvert<QColor>());
+  if (v.canConvert<QColor>())
+    {
+    return v.value<QColor>();
+    }
+  else
+    {
+    //black background
+    QColor defaultColor(0., 0., 0.);
+    return defaultColor;
+    }
+  return QColor();
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::computeRangeXDiff(const QRectF& rect, qreal rangeX[2])
+{
+  return rect.width() / (rangeX[1] - rangeX[0]);
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::computeRangeXOffset(qreal rangeX[2])
+{
+  return rangeX[0];
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::computeRangeYDiff(const QRectF& rect, const QVariant rangeY[2])
+{
+  qreal rangeYDiff = rect.height();
+  qreal rangePosY[2];
+  rangePosY[0] = this->posY(rangeY[0]);
+  rangePosY[1] = this->posY(rangeY[1]);
+  if (rangePosY[1] == rangePosY[0])
+    {
+    rangeYDiff /= rangePosY[0];
+    return rangeYDiff;
+    }
+  rangeYDiff /= rangePosY[1] - rangePosY[0];
+  return rangeYDiff;
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::computeRangeYOffset(const QVariant rangeY[2])
+{
+  qreal rangePosY[2];
+  rangePosY[0] = this->posY(rangeY[0]);
+  rangePosY[1] = this->posY(rangeY[1]);
+
+  if (rangePosY[1] == rangePosY[0])
+    {
+    return 0.;
+    }
+  return rangePosY[0];
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::posX(const qreal& x)const
+{
+  return x;
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::posY(const QVariant& value)const
+{
+  Q_ASSERT(value.canConvert<qreal>() || value.canConvert<QColor>());
+  if (value.canConvert<QColor>())
+    {
+    return value.value<QColor>().alphaF();
+    }
+  return value.toReal();
+}
+
+//-----------------------------------------------------------------------------
+QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkControlPoint* cp)const
+{
+  return QPointF(this->mapXToScreen(this->posX(cp->x())),
+                 this->mapYToScreen(this->posY(cp->value())));
+}
+
+//-----------------------------------------------------------------------------
+QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkPoint& point)const
+{
+  return QPointF( this->mapXToScreen(this->posX(point.X)),
+                  this->mapYToScreen(this->posY(point.Value)));
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::mapXToScreen(qreal xPos)const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  return (xPos - d->RangeXOffSet) * d->RangeXDiff;
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::mapYToScreen(qreal yPos)const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  return this->height() - (yPos - d->RangeYOffSet) * d->RangeYDiff;
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::mapXFromScreen(qreal screenPosX)const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  return (screenPosX / d->RangeXDiff) + d->RangeXOffSet;
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkTransferFunctionScene::mapYFromScreen(qreal screenPosY)const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  return ((this->height() - screenPosY) / d->RangeYDiff) + d->RangeYOffSet ;
+}

+ 81 - 0
Libs/Widgets/ctkTransferFunctionScene.h

@@ -0,0 +1,81 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  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.commontk.org/LICENSE
+
+  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.
+ 
+=========================================================================*/
+
+#ifndef __ctkTransferFunctionScene_h
+#define __ctkTransferFunctionScene_h
+
+/// Qt includes
+#include <QGraphicsScene>
+
+/// CTK includes
+#include "CTKWidgetsExport.h"
+#include "ctkPimpl.h"
+
+class ctkTransferFunction;
+class ctkTransferFunctionScenePrivate;
+class ctkControlPoint;
+class ctkPoint;
+
+//-----------------------------------------------------------------------------
+class CTK_WIDGETS_EXPORT ctkTransferFunctionScene: public QGraphicsScene
+{
+  Q_OBJECT;
+public:
+  ctkTransferFunctionScene(QObject* parent = 0);
+  ctkTransferFunctionScene(ctkTransferFunction* transferFunction, QObject* parent = 0);
+  virtual ~ctkTransferFunctionScene();
+
+  void setTransferFunction(ctkTransferFunction* transferFunction);
+  ctkTransferFunction* transferFunction()const;
+
+  qreal y(const QVariant& v) const;
+  QColor color(const QVariant& v) const;
+
+  qreal posX(const qreal& x)const;
+  qreal posY(const QVariant& value)const;
+  
+  QPointF mapPointToScreen(const ctkControlPoint* cp)const;
+  QPointF mapPointToScreen(const ctkPoint& point)const;
+ 
+  qreal mapXToScreen(qreal posX)const;
+  qreal mapYToScreen(qreal posY)const;
+  qreal mapXFromScreen(qreal screenPosX)const;
+  qreal mapYFromScreen(qreal screenPosY)const;
+
+  QList<ctkPoint> bezierParams(ctkControlPoint* start, ctkControlPoint* end) const;
+  QList<ctkPoint> nonLinearPoints(ctkControlPoint* start, ctkControlPoint* end) const;
+
+  const QPainterPath& curve()const;
+  const QList<QPointF>& points()const;
+  void computeCurve();
+
+protected slots:
+  virtual void onTransferFunctionChanged();
+
+protected:
+  qreal computeRangeXDiff(const QRectF& rect, qreal rangeX[2]);
+  qreal computeRangeXOffset(qreal rangeX[2]);
+  qreal computeRangeYDiff(const QRectF& rect, const QVariant rangeY[2]);
+  qreal computeRangeYOffset(const QVariant rangeY[2]);
+private:
+  CTK_DECLARE_PRIVATE(ctkTransferFunctionScene);
+};
+
+#endif

+ 28 - 9
Libs/Widgets/ctkTransferFunctionWidget.cpp

@@ -18,14 +18,15 @@
  
 =========================================================================*/
 /// Qt includes
+#include <QDebug>
+//#include <QGLWidget>
 #include <QGraphicsScene>
 #include <QResizeEvent>
-#include <QDebug>
 
 /// CTK includes
 #include "ctkTransferFunction.h"
 #include "ctkTransferFunctionWidget.h"
-#include "ctkTransferFunctionItem.h"
+#include "ctkTransferFunctionScene.h"
 #include "ctkTransferFunctionGradientItem.h"
 #include "ctkTransferFunctionControlPointsItem.h"
 
@@ -34,17 +35,25 @@ class ctkTransferFunctionWidgetPrivate: public ctkPrivate<ctkTransferFunctionWid
 {
   CTK_DECLARE_PUBLIC(ctkTransferFunctionWidget);
 public:
+  ctkTransferFunctionWidgetPrivate();
   void init();
   ctkTransferFunction* TransferFunction;
 };
 
 //-----------------------------------------------------------------------------
+ctkTransferFunctionWidgetPrivate::ctkTransferFunctionWidgetPrivate()
+{
+  this->TransferFunction = 0;
+}
+
+//-----------------------------------------------------------------------------
 void ctkTransferFunctionWidgetPrivate::init()
 {
   CTK_P(ctkTransferFunctionWidget);
-  p->setScene(new QGraphicsScene(p));
+  p->setScene(new ctkTransferFunctionScene(p));
   p->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   p->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+  //p->setViewport(new QGLWidget);
 }
 
 //-----------------------------------------------------------------------------
@@ -74,15 +83,19 @@ void ctkTransferFunctionWidget::setTransferFunction(ctkTransferFunction* transfe
 {
   CTK_D(ctkTransferFunctionWidget);
   d->TransferFunction = transferFunction;
-  Q_ASSERT(this->scene());
-  this->scene()->clear();
+  ctkTransferFunctionScene* tfScene = dynamic_cast<ctkTransferFunctionScene*>(this->scene());
+  Q_ASSERT(tfScene);
+  tfScene->clear();
+  tfScene->setTransferFunction(transferFunction);
+
   ctkTransferFunctionGradientItem* gradient = 
     new ctkTransferFunctionGradientItem(transferFunction);
-  gradient->setRect(0, 0, this->width(), this->height());
+  //gradient->setRect(tfScene->sceneRect());
   this->scene()->addItem(gradient);
+
   ctkTransferFunctionControlPointsItem* controlPoints = 
     new ctkTransferFunctionControlPointsItem(transferFunction);
-  controlPoints->setRect(0, 0, this->width(), this->height());
+  //controlPoints->setRect(tfScene->sceneRect());
   this->scene()->addItem(controlPoints);
 }
 
@@ -95,7 +108,9 @@ ctkTransferFunction* ctkTransferFunctionWidget::transferFunction()const
 //-----------------------------------------------------------------------------
 void ctkTransferFunctionWidget::resizeEvent(QResizeEvent * event)
 {
+  /*
   QRectF sceneRect(QPointF(0,0),event->size());
+  this->scene()->setSceneRect(sceneRect);
   foreach(QGraphicsItem * item, this->scene()->items())
     {
     ctkTransferFunctionItem* rectItem = 
@@ -105,8 +120,12 @@ void ctkTransferFunctionWidget::resizeEvent(QResizeEvent * event)
       rectItem->setRect(sceneRect);
       }
     }
-  this->scene()->setSceneRect(sceneRect);
-  
+  */
+  QMatrix zoomMatrix;
+  zoomMatrix.scale(event->size().width(), event->size().height());
+  bool blocked = this->blockSignals(true);
+  this->setMatrix(zoomMatrix);
+  this->blockSignals(blocked);
   this->QGraphicsView::resizeEvent(event);
   // Control points are resized by the view transform, we want
   // fixed size control points, lines...