|
|
@@ -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);
|
|
|
@@ -145,7 +164,7 @@ void ctkTransferFunctionScene::computeCurve()
|
|
|
ctkControlPoint* startCP = d->TransferFunction->controlPoint(0);
|
|
|
ctkControlPoint* nextCP = 0;
|
|
|
|
|
|
- QPointF startPos = this->mapPointToScreen(startCP);
|
|
|
+ QPointF startPos = this->mapPointToScene(startCP);
|
|
|
|
|
|
d->Points.clear();
|
|
|
d->Points << startPos;
|
|
|
@@ -161,10 +180,10 @@ void ctkTransferFunctionScene::computeCurve()
|
|
|
int j;
|
|
|
for (j = 1; j < points.count(); ++j)
|
|
|
{
|
|
|
- d->Path.lineTo(this->mapPointToScreen(points[j]));
|
|
|
+ d->Path.lineTo(this->mapPointToScene(points[j]));
|
|
|
}
|
|
|
j = points.count() - 1;
|
|
|
- d->Points << this->mapPointToScreen(points[j]);
|
|
|
+ d->Points << this->mapPointToScene(points[j]);
|
|
|
}
|
|
|
else //dynamic_cast<ctkBezierControlPoint*>(startCP))
|
|
|
{
|
|
|
@@ -173,7 +192,7 @@ void ctkTransferFunctionScene::computeCurve()
|
|
|
QList<QPointF> bezierPoints;
|
|
|
foreach(const ctkPoint& p, points)
|
|
|
{
|
|
|
- bezierPoints << this->mapPointToScreen(p);
|
|
|
+ bezierPoints << this->mapPointToScene(p);
|
|
|
}
|
|
|
d->Path.cubicTo(bezierPoints[1], bezierPoints[2], bezierPoints[3]);
|
|
|
d->Points << bezierPoints[3];
|
|
|
@@ -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->mapXToScene(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->mapXToScene(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->mapXToScene(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->mapXToScene(this->posX(p)), this->color(p));
|
|
|
+ }
|
|
|
+ nextPos = this->mapXToScene(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
|
|
|
{
|
|
|
@@ -320,43 +399,43 @@ qreal ctkTransferFunctionScene::posY(const QVariant& value)const
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkControlPoint* cp)const
|
|
|
+QPointF ctkTransferFunctionScene::mapPointToScene(const ctkControlPoint* cp)const
|
|
|
{
|
|
|
- return QPointF(this->mapXToScreen(this->posX(cp->x())),
|
|
|
- this->mapYToScreen(this->posY(cp->value())));
|
|
|
+ return QPointF(this->mapXToScene(this->posX(cp->x())),
|
|
|
+ this->mapYToScene(this->posY(cp->value())));
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkPoint& point)const
|
|
|
+QPointF ctkTransferFunctionScene::mapPointToScene(const ctkPoint& point)const
|
|
|
{
|
|
|
- return QPointF( this->mapXToScreen(this->posX(point.X)),
|
|
|
- this->mapYToScreen(this->posY(point.Value)));
|
|
|
+ return QPointF( this->mapXToScene(this->posX(point.X)),
|
|
|
+ this->mapYToScene(this->posY(point.Value)));
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-qreal ctkTransferFunctionScene::mapXToScreen(qreal xPos)const
|
|
|
+qreal ctkTransferFunctionScene::mapXToScene(qreal xPos)const
|
|
|
{
|
|
|
CTK_D(const ctkTransferFunctionScene);
|
|
|
return (xPos - d->RangeXOffSet) * d->RangeXDiff;
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-qreal ctkTransferFunctionScene::mapYToScreen(qreal yPos)const
|
|
|
+qreal ctkTransferFunctionScene::mapYToScene(qreal yPos)const
|
|
|
{
|
|
|
CTK_D(const ctkTransferFunctionScene);
|
|
|
return this->height() - (yPos - d->RangeYOffSet) * d->RangeYDiff;
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-qreal ctkTransferFunctionScene::mapXFromScreen(qreal screenPosX)const
|
|
|
+qreal ctkTransferFunctionScene::mapXFromScene(qreal scenePosX)const
|
|
|
{
|
|
|
CTK_D(const ctkTransferFunctionScene);
|
|
|
- return (screenPosX / d->RangeXDiff) + d->RangeXOffSet;
|
|
|
+ return (scenePosX / d->RangeXDiff) + d->RangeXOffSet;
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-qreal ctkTransferFunctionScene::mapYFromScreen(qreal screenPosY)const
|
|
|
+qreal ctkTransferFunctionScene::mapYFromScene(qreal scenePosY)const
|
|
|
{
|
|
|
CTK_D(const ctkTransferFunctionScene);
|
|
|
- return ((this->height() - screenPosY) / d->RangeYDiff) + d->RangeYOffSet ;
|
|
|
+ return ((this->height() - scenePosY) / d->RangeYDiff) + d->RangeYOffSet ;
|
|
|
}
|