ctkTransferFunctionItems.cpp

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Library:   CTK
00004  
00005   Copyright (c) 2010  Kitware Inc.
00006 
00007   Licensed under the Apache License, Version 2.0 (the "License");
00008   you may not use this file except in compliance with the License.
00009   You may obtain a copy of the License at
00010 
00011       http://www.commontk.org/LICENSE
00012 
00013   Unless required by applicable law or agreed to in writing, software
00014   distributed under the License is distributed on an "AS IS" BASIS,
00015   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016   See the License for the specific language governing permissions and
00017   limitations under the License.
00018  
00019 =========================================================================*/
00020 
00022 #include <QColor>
00023 #include <QDebug>
00024 #include <QLinearGradient>
00025 #include <QGraphicsSceneMouseEvent>
00026 #include <QPainter>
00027 #include <QtGlobal>
00028 #include <QVariant>
00029 
00031 #include "ctkTransferFunction.h"
00032 #include "ctkTransferFunctionItems.h"
00033 
00034 //-----------------------------------------------------------------------------
00035 class ctkTransferFunctionItemPrivate : 
00036   public ctkPrivate<ctkTransferFunctionItem>
00037 {
00038 public:
00039   ctkTransferFunctionItemPrivate();
00040 
00041   QRectF               Rect;
00042   ctkTransferFunction* TransferFunction;
00043 };
00044 
00045 //-----------------------------------------------------------------------------
00046 ctkTransferFunctionItemPrivate::ctkTransferFunctionItemPrivate()
00047 {
00048   this->TransferFunction = 0;
00049 }
00050 
00051 //-----------------------------------------------------------------------------
00052 ctkTransferFunctionItem::ctkTransferFunctionItem(QGraphicsItem* parentGraphicsItem)
00053   :QGraphicsObject(parentGraphicsItem)
00054 {
00055   CTK_INIT_PRIVATE(ctkTransferFunctionItem);
00056 }
00057 
00058 //-----------------------------------------------------------------------------
00059 ctkTransferFunctionItem::ctkTransferFunctionItem(
00060   ctkTransferFunction* transferFunction, QGraphicsItem* parentItem)
00061   :QGraphicsObject(parentItem)
00062 {
00063   CTK_INIT_PRIVATE(ctkTransferFunctionItem);
00064   this->setTransferFunction(transferFunction);
00065 }
00066 
00067 //-----------------------------------------------------------------------------
00068 ctkTransferFunctionItem::~ctkTransferFunctionItem()
00069 {
00070   
00071 }
00072 
00073 //-----------------------------------------------------------------------------
00074 void ctkTransferFunctionItem::setTransferFunction(ctkTransferFunction* transferFunction)
00075 {
00076   CTK_D(ctkTransferFunctionItem);
00077   if (d->TransferFunction == transferFunction)
00078     {
00079     return;
00080     }
00081   d->TransferFunction = transferFunction;
00082   connect(d->TransferFunction, SIGNAL(changed()),
00083           this, SLOT(onTransferFunctionChanged()));
00084   this->update();
00085 }
00086 
00087 //-----------------------------------------------------------------------------
00088 ctkTransferFunction* ctkTransferFunctionItem::transferFunction() const
00089 {
00090   CTK_D(const ctkTransferFunctionItem);
00091   return d->TransferFunction;
00092 }
00093 
00094 //-----------------------------------------------------------------------------
00095 void ctkTransferFunctionItem::onTransferFunctionChanged()
00096 {
00097   this->update();
00098 }
00099 
00100 //-----------------------------------------------------------------------------
00101 void ctkTransferFunctionItem::setRect(const QRectF& newRect)
00102 {
00103   CTK_D(ctkTransferFunctionItem);
00104   if (d->Rect == newRect)
00105     {
00106     return;
00107     }
00108   d->Rect = newRect;
00109   this->update();
00110 }
00111 
00112 //-----------------------------------------------------------------------------
00113 QRectF ctkTransferFunctionItem::rect() const
00114 {
00115   CTK_D(const ctkTransferFunctionItem);
00116   return d->Rect;
00117 }
00118 
00119 //-----------------------------------------------------------------------------
00120 QRectF ctkTransferFunctionItem::boundingRect()const
00121 {
00122   CTK_D(const ctkTransferFunctionItem);
00123   return d->Rect;
00124 }
00125 
00126 //-----------------------------------------------------------------------------
00127 QList<ctkPoint> ctkTransferFunctionItem::bezierParams(
00128   ctkControlPoint* start, ctkControlPoint* end) const
00129 {
00130   Q_ASSERT(start);
00131   Q_ASSERT(end);
00132   QList<ctkPoint> points; 
00133   
00134   ctkBezierControlPoint* bezierCP = dynamic_cast<ctkBezierControlPoint*>(start);
00135   if (!bezierCP)
00136     {// just duplicate start and end into p1 and p2
00137     points << start->P;
00138     points << start->P;
00139     points << end->P;
00140     points << end->P;
00141     return points;
00142     }
00143   
00144   points << start->P;
00145   points << bezierCP->P1;
00146   points << bezierCP->P2;
00147   points << end->P;
00148   return points;
00149 }
00150 
00151 //-----------------------------------------------------------------------------
00152 QList<ctkPoint> ctkTransferFunctionItem::nonLinearPoints(
00153   ctkControlPoint* start, ctkControlPoint* end) const
00154 {
00155   Q_ASSERT(start);
00156     
00157   ctkNonLinearControlPoint* nonLinearCP = 
00158     dynamic_cast<ctkNonLinearControlPoint*>(start);
00159   if (!nonLinearCP)
00160     {
00161     QList<ctkPoint> points; 
00162     points << start->P;
00163     points << end->P;
00164     return points;
00165     }
00166   return nonLinearCP->SubPoints;
00167 }
00168 
00169 //-----------------------------------------------------------------------------
00170 qreal ctkTransferFunctionItem::y(const QVariant& v) const
00171 { 
00172   Q_ASSERT(v.canConvert<qreal>() || v.canConvert<QColor>());
00173   if (v.canConvert<QColor>())
00174     {
00175     return v.value<QColor>().alphaF();
00176     }
00177   return v.toReal();
00178 }
00179 
00180 //-----------------------------------------------------------------------------
00181 QColor ctkTransferFunctionItem::color(const QVariant& v) const
00182 { 
00183   Q_ASSERT(v.canConvert<QColor>());
00184   if (v.canConvert<QColor>())
00185     {
00186     return v.value<QColor>();
00187     }
00188   return QColor();
00189 }
00190 
00191 //-----------------------------------------------------------------------------
00192 ctkTransferFunctionGradientItem::ctkTransferFunctionGradientItem(QGraphicsItem* parentGraphicsItem)
00193   :ctkTransferFunctionItem(parentGraphicsItem)
00194 {
00195 }
00196 
00197 //-----------------------------------------------------------------------------
00198 ctkTransferFunctionGradientItem::ctkTransferFunctionGradientItem(
00199   ctkTransferFunction* transferFunction, QGraphicsItem* parentItem)
00200   :ctkTransferFunctionItem(transferFunction, parentItem)
00201 {
00202 }
00203 
00204 //-----------------------------------------------------------------------------
00205 ctkTransferFunctionGradientItem::~ctkTransferFunctionGradientItem()
00206 {  
00207 }
00208 
00209 //-----------------------------------------------------------------------------
00210 void ctkTransferFunctionGradientItem::paint(
00211   QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
00212 {
00213   int count = this->transferFunction() ? this->transferFunction()->count() : 0;
00214   if (count <= 0)
00215     {
00216     painter->fillRect(this->rect(),Qt::black);
00217     return;
00218     }
00219   qreal range[2];
00220   this->transferFunction()->range(range);
00221   qreal rangeDiff = this->rect().width() / (range[1] - range[0]);
00222   ctkControlPoint* startCP = this->transferFunction()->controlPoint(0);
00223   ctkControlPoint* endCP = 0;
00224   
00225   qreal start = startCP->x() * rangeDiff;
00226   qreal end = 0;
00227   for(int i = 1; i < count; ++i)
00228     {
00229     endCP = this->transferFunction()->controlPoint(i);
00230     // TODO, handle Bezier points for a finer gradient
00231     // TODO, handle nonlinear points
00232     if (dynamic_cast<ctkNonLinearControlPoint*>(startCP) != 0)
00233       {
00234       QList<ctkPoint> points = this->nonLinearPoints(startCP, endCP);
00235       for (int j = 1; j < points.count(); ++j)
00236         {
00237         end = points[j].X * rangeDiff;
00238         QLinearGradient gradient(start, 0, end, 0);
00239         gradient.setColorAt(0, this->color(points[j-1]));
00240         gradient.setColorAt(1, this->color(points[j]));
00241         QRectF itemRect = QRectF(start, 0, end - start, 
00242                                  this->rect().height());
00243         if (i==1 && j == 1)
00244           {
00245           itemRect.setLeft(0.);
00246           }
00247         if ((i == count -1) && (j == points.count() -1))
00248           {
00249           itemRect.setRight(this->rect().width());
00250           }
00251         painter->fillRect(itemRect, gradient);
00252         start = end;
00253         }
00254       }
00255     else
00256       {
00257       end = endCP->x() * rangeDiff;
00258       QLinearGradient gradient(start, 0, end, 0);
00259       gradient.setColorAt(0, this->color(startCP->value()));
00260       gradient.setColorAt(1, this->color(endCP->value()));
00261       QRectF itemRect = QRectF(start, 0, end - start, 
00262                                this->rect().height());
00263       if (i==1)
00264         {
00265         itemRect.setLeft(0.);
00266         }
00267       if (i == count -1)
00268         {
00269         itemRect.setRight(this->rect().width());
00270         }
00271       painter->fillRect(itemRect, gradient);
00272       }
00273     delete startCP;
00274     startCP = endCP;
00275     start = end;
00276     }
00277   if (startCP)
00278     {
00279     delete startCP;
00280     }
00281 }
00282 
00283 //-----------------------------------------------------------------------------
00284 class ctkTransferFunctionControlPointsItemPrivate: 
00285   public ctkPrivate<ctkTransferFunctionControlPointsItem>
00286 {
00287 public:
00288   ctkTransferFunctionControlPointsItemPrivate();
00289   void init();
00290   QList<QPointF> ControlPoints;
00291   QSizeF         PointSize;
00292   int            SelectedPoint;
00293 };
00294 
00295 //-----------------------------------------------------------------------------
00296 ctkTransferFunctionControlPointsItemPrivate::ctkTransferFunctionControlPointsItemPrivate()
00297 {
00298   this->PointSize = QSizeF(10.,10.);
00299   this->SelectedPoint = -1;
00300 }
00301 
00302 //-----------------------------------------------------------------------------
00303 void ctkTransferFunctionControlPointsItemPrivate::init()
00304 {
00305   CTK_P(ctkTransferFunctionControlPointsItem);
00306   p->setAcceptedMouseButtons(Qt::LeftButton);
00307 }
00308 
00309 //-----------------------------------------------------------------------------
00310 ctkTransferFunctionControlPointsItem::ctkTransferFunctionControlPointsItem(QGraphicsItem* parentGraphicsItem)
00311   :ctkTransferFunctionItem(parentGraphicsItem)
00312 {
00313   CTK_INIT_PRIVATE(ctkTransferFunctionControlPointsItem);
00314   ctk_d()->init();
00315 }
00316 
00317 //-----------------------------------------------------------------------------
00318 ctkTransferFunctionControlPointsItem::ctkTransferFunctionControlPointsItem(
00319   ctkTransferFunction* transferFunction, QGraphicsItem* parentItem)
00320   :ctkTransferFunctionItem(transferFunction, parentItem)
00321 {
00322   CTK_INIT_PRIVATE(ctkTransferFunctionControlPointsItem);
00323   ctk_d()->init();
00324 }
00325 
00326 //-----------------------------------------------------------------------------
00327 ctkTransferFunctionControlPointsItem::~ctkTransferFunctionControlPointsItem()
00328 {  
00329 }
00330 
00331 //-----------------------------------------------------------------------------
00332 void ctkTransferFunctionControlPointsItem::paint(
00333   QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
00334 {
00335   CTK_D(ctkTransferFunctionControlPointsItem);
00336   int count = this->transferFunction() ? this->transferFunction()->count() : 0;
00337   if (count <= 0)
00338     {
00339     return;
00340     }
00341   qreal rangeX[2];
00342   this->transferFunction()->range(rangeX);
00343   qreal rangeXDiff = this->rect().width() / (rangeX[1] - rangeX[0]);
00344   QVariant rangeY[2];
00345   rangeY[0] = this->transferFunction()->minValue();
00346   rangeY[1] = this->transferFunction()->maxValue();
00347   qreal rangeYDiff = this->rect().height();
00348   if (rangeY[0].canConvert<qreal>())
00349     {
00350     rangeYDiff /= rangeY[1].toReal() - rangeY[0].toReal();
00351     }
00352   else if (rangeY[0].canConvert<qreal>())
00353     {
00354     rangeYDiff /= rangeY[1].value<QColor>().alphaF() - rangeY[0].value<QColor>().alphaF();
00355     }
00356   else
00357     {
00358     Q_ASSERT(rangeY[0].canConvert<qreal>() ||
00359              rangeY[0].canConvert<QColor>());
00360     }
00361   ctkControlPoint* startCP = this->transferFunction()->controlPoint(0);
00362   ctkControlPoint* endCP = 0;
00363   qreal start = 0;
00364   qreal end = 0;
00365 
00366   QPainterPath path;
00367 
00368   QPointF startPos(startCP->x(), this->y(startCP->value()));
00369   startPos.rx() *= rangeXDiff;
00370   startPos.setY(this->rect().height() 
00371                 - startPos.y() * rangeYDiff);
00372   
00373   d->ControlPoints.clear();
00374   d->ControlPoints << startPos;
00375 
00376   path.moveTo(startPos);
00377   for(int i = 1; i < count; ++i)
00378     {
00379     endCP = this->transferFunction()->controlPoint(i);
00380     if (dynamic_cast<ctkNonLinearControlPoint*>(startCP))
00381       {
00382       QList<ctkPoint> points = this->nonLinearPoints(startCP, endCP);
00383       int j;
00384       for (j = 1; j < points.count(); ++j)
00385         {
00386         path.lineTo(
00387           QPointF(points[j].X * rangeXDiff, this->rect().height() - 
00388                   this->y(points[j].Value) * rangeYDiff));
00389         }
00390       j = points.count() -1;
00391       d->ControlPoints << QPointF(points[j].X * rangeXDiff, this->rect().height() - 
00392                   this->y(points[j].Value) * rangeYDiff);
00393       }
00394     else //dynamic_cast<ctkBezierControlPoint*>(startCP))
00395       {
00396       QList<ctkPoint> points = this->bezierParams(startCP, endCP);
00397       QList<ctkPoint>::iterator it = points.begin();
00398       QList<QPointF> bezierPoints;
00399       foreach(const ctkPoint& p, points)
00400         {
00401         bezierPoints << 
00402           QPointF(p.X * rangeXDiff, 
00403                   this->rect().height() - this->y(p.Value) * rangeYDiff);
00404         }
00405       path.cubicTo(bezierPoints[1], bezierPoints[2], bezierPoints[3]);
00406       d->ControlPoints << bezierPoints[3];
00407       }
00408     //qDebug() << i << points[0] << points[1] << points[2] << points[3];
00409     delete startCP;
00410     startCP = endCP;
00411     }
00412   if (startCP)
00413     {
00414     delete startCP;
00415     }
00416   painter->setRenderHint(QPainter::Antialiasing);
00417   painter->setPen(QPen(QColor(255, 255, 255, 191), 1));
00418   painter->drawPath(path);
00419 
00420   QPainterPath points;
00421   foreach(const QPointF& point, d->ControlPoints)
00422     {
00423     points.addEllipse(point, d->PointSize.width(), d->PointSize.height());
00424     }
00425   painter->setBrush(QBrush(QColor(191, 191, 191, 127)));
00426   painter->drawPath(points);
00427 }
00428 
00429 //-----------------------------------------------------------------------------
00430 void ctkTransferFunctionControlPointsItem::mousePressEvent(QGraphicsSceneMouseEvent* e)
00431 {
00432   CTK_D(ctkTransferFunctionControlPointsItem);
00433   QRectF pointArea(QPointF(0,0), d->PointSize*2.);
00434   d->SelectedPoint = -1;
00435   for(int i = 0; i < d->ControlPoints.count(); ++i)
00436     {
00437     pointArea.moveCenter(d->ControlPoints[i]);
00438     if (pointArea.contains(e->pos()))
00439       {
00440       d->SelectedPoint = i;
00441       break;
00442       }
00443     }
00444   if (d->SelectedPoint < 0)
00445     {
00446     e->ignore();
00447     }
00448 }
00449 
00450 //-----------------------------------------------------------------------------
00451 void ctkTransferFunctionControlPointsItem::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
00452 {
00453   CTK_D(ctkTransferFunctionControlPointsItem);
00454   if (d->SelectedPoint < 0)
00455     {
00456     e->ignore();
00457     return;
00458     }
00459   qreal range[2];
00460   this->transferFunction()->range(range);
00461   qreal newPos = range[0] + e->pos().x() / (this->rect().width() / (range[1] - range[0]));
00462   newPos = qBound(range[0], newPos, range[1]);
00463   this->transferFunction()->setControlPointPos(d->SelectedPoint, newPos);
00464   //this->transferFunction()->setControlPointValue(d->SelectedPoint, e->y());
00465 }
00466 
00467 //-----------------------------------------------------------------------------
00468 void ctkTransferFunctionControlPointsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* e)
00469 {
00470   CTK_D(ctkTransferFunctionControlPointsItem);
00471   if (d->SelectedPoint < 0)
00472     {
00473     e->ignore();
00474     return;
00475     }
00476   d->SelectedPoint = -1;
00477 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines