ctkTransferFunctionScene.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 2010 Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. /// Qt includes
  15. #include <QGraphicsScene>
  16. #include <QResizeEvent>
  17. #include <QDebug>
  18. /// CTK includes
  19. #include "ctkTransferFunction.h"
  20. #include "ctkTransferFunctionScene.h"
  21. //-----------------------------------------------------------------------------
  22. class ctkTransferFunctionScenePrivate: public ctkPrivate<ctkTransferFunctionScene>
  23. {
  24. CTK_DECLARE_PUBLIC(ctkTransferFunctionScene);
  25. public:
  26. ctkTransferFunctionScenePrivate();
  27. QRectF OldRect;
  28. ctkTransferFunction* TransferFunction;
  29. QPainterPath Path;
  30. QList<QPointF> Points;
  31. qreal WorldRangeX[2];
  32. QVariant WorldRangeY[2];
  33. qreal RangeXDiff;
  34. qreal RangeXOffSet;
  35. qreal RangeYDiff;
  36. qreal RangeYOffSet;
  37. };
  38. ctkTransferFunctionScenePrivate::ctkTransferFunctionScenePrivate()
  39. {
  40. this->TransferFunction = 0;
  41. }
  42. //-----------------------------------------------------------------------------
  43. ctkTransferFunctionScene::ctkTransferFunctionScene(QObject* parentObject)
  44. :QGraphicsScene(parentObject)
  45. {
  46. CTK_INIT_PRIVATE(ctkTransferFunctionScene);
  47. }
  48. //-----------------------------------------------------------------------------
  49. ctkTransferFunctionScene::ctkTransferFunctionScene(
  50. ctkTransferFunction* transferFunction, QObject* parentObject)
  51. :QGraphicsScene(parentObject)
  52. {
  53. CTK_INIT_PRIVATE(ctkTransferFunctionScene);
  54. this->setTransferFunction(transferFunction);
  55. }
  56. //-----------------------------------------------------------------------------
  57. ctkTransferFunctionScene::~ctkTransferFunctionScene()
  58. {
  59. }
  60. //-----------------------------------------------------------------------------
  61. void ctkTransferFunctionScene::setTransferFunction(ctkTransferFunction* transferFunction)
  62. {
  63. CTK_D(ctkTransferFunctionScene);
  64. if (d->TransferFunction == transferFunction)
  65. {
  66. return;
  67. }
  68. d->TransferFunction = transferFunction;
  69. connect( d->TransferFunction, SIGNAL(changed()),
  70. this, SLOT(onTransferFunctionChanged()),
  71. Qt::UniqueConnection);
  72. this->update();
  73. }
  74. //-----------------------------------------------------------------------------
  75. ctkTransferFunction* ctkTransferFunctionScene::transferFunction()const
  76. {
  77. return ctk_d()->TransferFunction;
  78. }
  79. //-----------------------------------------------------------------------------
  80. void ctkTransferFunctionScene::onTransferFunctionChanged()
  81. {
  82. CTK_D(ctkTransferFunctionScene);
  83. // TODO delete cache here
  84. d->Path = QPainterPath();
  85. this->update();
  86. }
  87. //-----------------------------------------------------------------------------
  88. const QPainterPath& ctkTransferFunctionScene::curve()const
  89. {
  90. CTK_D(const ctkTransferFunctionScene);
  91. if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
  92. {
  93. const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
  94. }
  95. return d->Path;
  96. }
  97. //-----------------------------------------------------------------------------
  98. const QList<QPointF>& ctkTransferFunctionScene::points()const
  99. {
  100. CTK_D(const ctkTransferFunctionScene);
  101. if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
  102. {
  103. const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
  104. }
  105. return d->Points;
  106. }
  107. //-----------------------------------------------------------------------------
  108. void ctkTransferFunctionScene::computeCurve()
  109. {
  110. CTK_D(ctkTransferFunctionScene);
  111. int count = d->TransferFunction ? d->TransferFunction->count() : 0;
  112. if (count <= 0)
  113. {
  114. return;
  115. }
  116. qDebug() << "computeCurve" << this->sceneRect();
  117. d->TransferFunction->range(d->WorldRangeX[0], d->WorldRangeX[1]);
  118. d->WorldRangeY[0] = this->y(d->TransferFunction->minValue());
  119. d->WorldRangeY[1] = this->y(d->TransferFunction->maxValue());
  120. d->RangeXDiff = this->computeRangeXDiff(this->sceneRect(), d->WorldRangeX);
  121. d->RangeXOffSet = this->computeRangeXOffset(d->WorldRangeX);
  122. d->RangeYDiff = this->computeRangeYDiff(this->sceneRect(), d->WorldRangeY);
  123. d->RangeYOffSet = this->computeRangeYOffset(d->WorldRangeY);
  124. ctkControlPoint* startCP = d->TransferFunction->controlPoint(0);
  125. ctkControlPoint* nextCP = 0;
  126. QPointF startPos = this->mapPointToScreen(startCP);
  127. d->Points.clear();
  128. d->Points << startPos;
  129. d->Path = QPainterPath();
  130. d->Path.moveTo(startPos);
  131. for(int i = 1; i < count; ++i)
  132. {
  133. nextCP = d->TransferFunction->controlPoint(i);
  134. if (dynamic_cast<ctkNonLinearControlPoint*>(startCP))
  135. {
  136. QList<ctkPoint> points = this->nonLinearPoints(startCP, nextCP);
  137. int j;
  138. for (j = 1; j < points.count(); ++j)
  139. {
  140. d->Path.lineTo(this->mapPointToScreen(points[j]));
  141. }
  142. j = points.count() - 1;
  143. d->Points << this->mapPointToScreen(points[j]);
  144. }
  145. else //dynamic_cast<ctkBezierControlPoint*>(startCP))
  146. {
  147. QList<ctkPoint> points = this->bezierParams(startCP, nextCP);
  148. QList<ctkPoint>::iterator it = points.begin();
  149. QList<QPointF> bezierPoints;
  150. foreach(const ctkPoint& p, points)
  151. {
  152. bezierPoints << this->mapPointToScreen(p);
  153. }
  154. d->Path.cubicTo(bezierPoints[1], bezierPoints[2], bezierPoints[3]);
  155. d->Points << bezierPoints[3];
  156. }
  157. //qDebug() << i << points[0] << points[1] << points[2] << points[3];
  158. delete startCP;
  159. startCP = nextCP;
  160. }
  161. if (startCP)
  162. {
  163. delete startCP;
  164. }
  165. }
  166. //-----------------------------------------------------------------------------
  167. QList<ctkPoint> ctkTransferFunctionScene::bezierParams(
  168. ctkControlPoint* start, ctkControlPoint* end) const
  169. {
  170. Q_ASSERT(start);
  171. Q_ASSERT(end);
  172. QList<ctkPoint> points;
  173. ctkBezierControlPoint* bezierCP = dynamic_cast<ctkBezierControlPoint*>(start);
  174. if (!bezierCP)
  175. {// just duplicate start and end into p1 and p2
  176. points << start->P;
  177. points << start->P;
  178. points << end->P;
  179. points << end->P;
  180. return points;
  181. }
  182. points << start->P;
  183. points << bezierCP->P1;
  184. points << bezierCP->P2;
  185. points << end->P;
  186. return points;
  187. }
  188. //-----------------------------------------------------------------------------
  189. QList<ctkPoint> ctkTransferFunctionScene::nonLinearPoints(
  190. ctkControlPoint* start, ctkControlPoint* end) const
  191. {
  192. Q_ASSERT(start);
  193. ctkNonLinearControlPoint* nonLinearCP =
  194. dynamic_cast<ctkNonLinearControlPoint*>(start);
  195. if (!nonLinearCP)
  196. {
  197. QList<ctkPoint> points;
  198. points << start->P;
  199. points << end->P;
  200. return points;
  201. }
  202. return nonLinearCP->SubPoints;
  203. }
  204. //-----------------------------------------------------------------------------
  205. qreal ctkTransferFunctionScene::y(const QVariant& v) const
  206. {
  207. Q_ASSERT(v.canConvert<qreal>() || v.canConvert<QColor>());
  208. if (v.canConvert<QColor>())
  209. {
  210. return v.value<QColor>().alphaF();
  211. }
  212. return v.toReal();
  213. }
  214. //-----------------------------------------------------------------------------
  215. QColor ctkTransferFunctionScene::color(const QVariant& v) const
  216. {
  217. //Q_ASSERT(v.canConvert<QColor>());
  218. if (v.canConvert<QColor>())
  219. {
  220. return v.value<QColor>();
  221. }
  222. else
  223. {
  224. //black background
  225. QColor defaultColor(0., 0., 0.);
  226. return defaultColor;
  227. }
  228. return QColor();
  229. }
  230. //-----------------------------------------------------------------------------
  231. qreal ctkTransferFunctionScene::computeRangeXDiff(const QRectF& rect, qreal rangeX[2])
  232. {
  233. return rect.width() / (rangeX[1] - rangeX[0]);
  234. }
  235. //-----------------------------------------------------------------------------
  236. qreal ctkTransferFunctionScene::computeRangeXOffset(qreal rangeX[2])
  237. {
  238. return rangeX[0];
  239. }
  240. //-----------------------------------------------------------------------------
  241. qreal ctkTransferFunctionScene::computeRangeYDiff(const QRectF& rect, const QVariant rangeY[2])
  242. {
  243. qreal rangeYDiff = rect.height();
  244. qreal rangePosY[2];
  245. rangePosY[0] = this->posY(rangeY[0]);
  246. rangePosY[1] = this->posY(rangeY[1]);
  247. if (rangePosY[1] == rangePosY[0])
  248. {
  249. rangeYDiff /= rangePosY[0];
  250. return rangeYDiff;
  251. }
  252. rangeYDiff /= rangePosY[1] - rangePosY[0];
  253. return rangeYDiff;
  254. }
  255. //-----------------------------------------------------------------------------
  256. qreal ctkTransferFunctionScene::computeRangeYOffset(const QVariant rangeY[2])
  257. {
  258. qreal rangePosY[2];
  259. rangePosY[0] = this->posY(rangeY[0]);
  260. rangePosY[1] = this->posY(rangeY[1]);
  261. if (rangePosY[1] == rangePosY[0])
  262. {
  263. return 0.;
  264. }
  265. return rangePosY[0];
  266. }
  267. //-----------------------------------------------------------------------------
  268. qreal ctkTransferFunctionScene::posX(const qreal& x)const
  269. {
  270. return x;
  271. }
  272. //-----------------------------------------------------------------------------
  273. qreal ctkTransferFunctionScene::posY(const QVariant& value)const
  274. {
  275. Q_ASSERT(value.canConvert<qreal>() || value.canConvert<QColor>());
  276. if (value.canConvert<QColor>())
  277. {
  278. return value.value<QColor>().alphaF();
  279. }
  280. return value.toReal();
  281. }
  282. //-----------------------------------------------------------------------------
  283. QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkControlPoint* cp)const
  284. {
  285. return QPointF(this->mapXToScreen(this->posX(cp->x())),
  286. this->mapYToScreen(this->posY(cp->value())));
  287. }
  288. //-----------------------------------------------------------------------------
  289. QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkPoint& point)const
  290. {
  291. return QPointF( this->mapXToScreen(this->posX(point.X)),
  292. this->mapYToScreen(this->posY(point.Value)));
  293. }
  294. //-----------------------------------------------------------------------------
  295. qreal ctkTransferFunctionScene::mapXToScreen(qreal xPos)const
  296. {
  297. CTK_D(const ctkTransferFunctionScene);
  298. return (xPos - d->RangeXOffSet) * d->RangeXDiff;
  299. }
  300. //-----------------------------------------------------------------------------
  301. qreal ctkTransferFunctionScene::mapYToScreen(qreal yPos)const
  302. {
  303. CTK_D(const ctkTransferFunctionScene);
  304. return this->height() - (yPos - d->RangeYOffSet) * d->RangeYDiff;
  305. }
  306. //-----------------------------------------------------------------------------
  307. qreal ctkTransferFunctionScene::mapXFromScreen(qreal screenPosX)const
  308. {
  309. CTK_D(const ctkTransferFunctionScene);
  310. return (screenPosX / d->RangeXDiff) + d->RangeXOffSet;
  311. }
  312. //-----------------------------------------------------------------------------
  313. qreal ctkTransferFunctionScene::mapYFromScreen(qreal screenPosY)const
  314. {
  315. CTK_D(const ctkTransferFunctionScene);
  316. return ((this->height() - screenPosY) / d->RangeYDiff) + d->RangeYOffSet ;
  317. }