ctkVTKCompositeFunction.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 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.apache.org/licenses/LICENSE-2.0.txt
  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 <QColor>
  16. #include <QDebug>
  17. /// CTK includes
  18. #include "ctkVTKCompositeFunction.h"
  19. /// VTK includes
  20. #include <vtkPiecewiseFunction.h>
  21. #include <vtkColorTransferFunction.h>
  22. #include <vtkSmartPointer.h>
  23. class ctkVTKCompositeFunctionPrivate
  24. {
  25. public:
  26. vtkSmartPointer<vtkPiecewiseFunction> PiecewiseFunction;
  27. vtkSmartPointer<vtkColorTransferFunction> ColorTransferFunction;
  28. };
  29. //-----------------------------------------------------------------------------
  30. ctkVTKCompositeFunction::ctkVTKCompositeFunction(vtkPiecewiseFunction* piecewiseFunction,
  31. vtkColorTransferFunction* colorTransferFunction,
  32. QObject* parentObject)
  33. :ctkTransferFunction(parentObject)
  34. , d_ptr(new ctkVTKCompositeFunctionPrivate)
  35. {
  36. this->setPiecewiseFunction(piecewiseFunction);
  37. this->setColorTransferFunction(colorTransferFunction);
  38. }
  39. //-----------------------------------------------------------------------------
  40. ctkVTKCompositeFunction::~ctkVTKCompositeFunction()
  41. {
  42. }
  43. //-----------------------------------------------------------------------------
  44. int ctkVTKCompositeFunction::count()const
  45. {
  46. Q_D(const ctkVTKCompositeFunction);
  47. // count points from piecewise
  48. // could be from color transfer function
  49. if (d->PiecewiseFunction.GetPointer() == 0)
  50. {
  51. Q_ASSERT(d->PiecewiseFunction.GetPointer());
  52. return -1;
  53. }
  54. if (d->ColorTransferFunction.GetPointer() == 0)
  55. {
  56. Q_ASSERT(d->ColorTransferFunction.GetPointer());
  57. return -1;
  58. }
  59. //qDebug() << "Piecewise: " << d->PiecewiseFunction->GetSize();
  60. //qDebug() << "Color Transfer: " << d->ColorTransferFunction->GetSize();
  61. // check if 2 tranfer function have same size
  62. Q_ASSERT( d->PiecewiseFunction->GetSize() == d->ColorTransferFunction->GetSize());
  63. return d->PiecewiseFunction->GetSize();
  64. }
  65. //-----------------------------------------------------------------------------
  66. bool ctkVTKCompositeFunction::isDiscrete()const
  67. {
  68. return false;
  69. }
  70. //-----------------------------------------------------------------------------
  71. bool ctkVTKCompositeFunction::isEditable()const
  72. {
  73. return true;
  74. }
  75. //-----------------------------------------------------------------------------
  76. void ctkVTKCompositeFunction::range(qreal& minRange, qreal& maxRange)const
  77. {
  78. Q_D(const ctkVTKCompositeFunction);
  79. if (d->PiecewiseFunction.GetPointer() == 0)
  80. {
  81. Q_ASSERT(d->PiecewiseFunction.GetPointer());
  82. minRange = 1.;
  83. maxRange = 0.;
  84. return;
  85. }
  86. double rangeValues[2];
  87. d->PiecewiseFunction->GetRange(rangeValues);
  88. minRange = rangeValues[0];
  89. maxRange = rangeValues[1];
  90. }
  91. //-----------------------------------------------------------------------------
  92. QVariant ctkVTKCompositeFunction::minValue()const
  93. {
  94. Q_D(const ctkVTKCompositeFunction);
  95. if (d->PiecewiseFunction.GetPointer() == 0)
  96. {
  97. Q_ASSERT(d->PiecewiseFunction.GetPointer());
  98. return -1;
  99. }
  100. //Initialize to max value
  101. double minValue = VTK_DOUBLE_MAX;
  102. for (int i = 0; i < this->count(); ++i)
  103. {
  104. double value[4];
  105. d->PiecewiseFunction->GetNodeValue(i, value);
  106. minValue = qMin(value[1], minValue);
  107. }
  108. return minValue;
  109. }
  110. //-----------------------------------------------------------------------------
  111. QVariant ctkVTKCompositeFunction::maxValue()const
  112. {
  113. Q_D(const ctkVTKCompositeFunction);
  114. if (d->PiecewiseFunction.GetPointer() == 0)
  115. {
  116. Q_ASSERT(d->PiecewiseFunction.GetPointer());
  117. return -1;
  118. }
  119. //Initialize to min value
  120. double maxValue = VTK_DOUBLE_MIN;
  121. for (int i = 0; i < this->count(); ++i)
  122. {
  123. double value[4];
  124. d->PiecewiseFunction->GetNodeValue(i, value);
  125. maxValue = qMax(maxValue, value[1]);
  126. }
  127. return maxValue;
  128. }
  129. //-----------------------------------------------------------------------------
  130. ctkControlPoint* ctkVTKCompositeFunction::controlPoint(int index)const
  131. {
  132. Q_D(const ctkVTKCompositeFunction);
  133. Q_ASSERT(index >= 0 && index < this->count());
  134. double valuesPWF[4];
  135. double valuesCTF[6];
  136. #ifndef QT_NO_DEBUG
  137. double* rangePWF = d->PiecewiseFunction->GetRange();
  138. double* rangeCTF = d->ColorTransferFunction->GetRange();
  139. #endif
  140. d->PiecewiseFunction->GetNodeValue(index, valuesPWF);
  141. d->ColorTransferFunction->GetNodeValue(index, valuesCTF);
  142. QVariant rangeY[2];
  143. rangeY[0] = this->minValue();
  144. rangeY[1] = this->maxValue();
  145. // test piecewise
  146. Q_ASSERT(valuesPWF[0] >= rangePWF[0] && valuesPWF[0] <= rangePWF [1] && // X
  147. valuesPWF[1] >= rangeY[0].toDouble() && valuesPWF[1] <= rangeY[1].toDouble() && // Y
  148. valuesPWF[2] >= 0. && valuesPWF[2] <= 1. && // Midpoint
  149. valuesPWF[3] >= 0. && valuesPWF[3] <= 1. ); // Sharpness
  150. // test color transfer
  151. Q_ASSERT(valuesCTF[0] >= rangeCTF[0] &&
  152. valuesCTF[0] <= rangeCTF[1] &&
  153. valuesCTF[1] >= 0. && valuesCTF[1] <= 1. && // Red
  154. valuesCTF[2] >= 0. && valuesCTF[2] <= 1. && // Green
  155. valuesCTF[3] >= 0. && valuesCTF[3] <= 1. && // Blue
  156. valuesCTF[4] >= 0. && valuesCTF[4] <= 1. && // MidPoint
  157. valuesCTF[5] >= 0. && valuesCTF[5] <= 1.); // Sharpness
  158. // if only 2 points -> linear
  159. if (index + 1 >= this->count())
  160. {
  161. ctkControlPoint* cp = new ctkControlPoint();
  162. cp->P.X = valuesPWF[0];
  163. // update value of QVariant
  164. cp->P.Value = QColor::fromRgbF(
  165. valuesCTF[1], valuesCTF[2], valuesCTF[3], valuesPWF[1]);
  166. return cp;
  167. }
  168. //else
  169. ctkNonLinearControlPoint* cp = new ctkNonLinearControlPoint();
  170. cp->P.X = valuesPWF[0];
  171. // update value of QVariant
  172. cp->P.Value = QColor::fromRgbF(valuesCTF[1], valuesCTF[2], valuesCTF[3], valuesPWF[1]);
  173. double nextValuesPWF[4], nextValuesCTF[6];
  174. d->PiecewiseFunction->GetNodeValue(index + 1, nextValuesPWF);
  175. d->ColorTransferFunction->GetNodeValue(index + 1, nextValuesCTF);
  176. Q_ASSERT(nextValuesPWF[0] >= rangePWF[0] && nextValuesPWF[0] <= rangePWF[1] && // X
  177. nextValuesPWF[1] >= rangeY[0].toDouble() && nextValuesPWF[1] <= rangeY[1].toDouble() && // Y
  178. nextValuesPWF[2] >= 0. && nextValuesPWF[2] <= 1. && // Midpoint
  179. nextValuesPWF[3] >= 0. && nextValuesPWF[3] <= 1. ); // Sharpness
  180. Q_ASSERT(nextValuesCTF[0] >= rangeCTF[0] &&
  181. nextValuesCTF[0] <= rangeCTF[1] &&
  182. nextValuesCTF[1] >= 0. && nextValuesCTF[1] <= 1. && // Red
  183. nextValuesCTF[2] >= 0. && nextValuesCTF[2] <= 1. && // Green
  184. nextValuesCTF[3] >= 0. && nextValuesCTF[3] <= 1. && // Blue
  185. nextValuesCTF[4] >= 0. && nextValuesCTF[4] <= 1. && // MidPoint
  186. nextValuesCTF[5] >= 0. && nextValuesCTF[5] <= 1.); // Sharpness
  187. // Optimization: don't use subPoints if the ramp is linear (sharpness == 0)
  188. if (valuesPWF[3] == 0. && valuesCTF[5] == 0.)
  189. {
  190. cp->SubPoints << ctkPoint(valuesPWF[0], QColor::fromRgbF(
  191. valuesCTF[1], valuesCTF[2], valuesCTF[3], valuesPWF[1]));
  192. cp->SubPoints << ctkPoint(nextValuesPWF[0], QColor::fromRgbF(
  193. nextValuesCTF[1], nextValuesCTF[2], nextValuesCTF[3], nextValuesPWF[1]));
  194. return cp;
  195. }
  196. double subPointsCTF[300];
  197. double subPointsPWF[100];
  198. d->ColorTransferFunction->GetTable(cp->x(), nextValuesCTF[0], 100, subPointsCTF);
  199. d->PiecewiseFunction->GetTable(cp->x(), nextValuesCTF[0], 100, subPointsPWF);
  200. qreal interval = (nextValuesCTF[0] - cp->x()) / 99.;
  201. for(int i = 0; i < 100; ++i)
  202. {
  203. qreal red = subPointsCTF[3*i];
  204. qreal green = subPointsCTF[3*i+1];
  205. qreal blue = subPointsCTF[3*i+2];
  206. qreal alpha = subPointsPWF[i];
  207. QColor compositeValue = QColor::fromRgbF(red, green, blue, alpha );
  208. cp->SubPoints << ctkPoint(cp->x() + interval*i, compositeValue);
  209. }
  210. return cp;
  211. }
  212. //-----------------------------------------------------------------------------
  213. QVariant ctkVTKCompositeFunction::value(qreal pos)const
  214. {
  215. Q_D(const ctkVTKCompositeFunction);
  216. Q_ASSERT(d->PiecewiseFunction.GetPointer());
  217. Q_ASSERT(d->ColorTransferFunction.GetPointer());
  218. // Get color
  219. double rgb[3];
  220. d->ColorTransferFunction->GetColor(pos, rgb);
  221. // Get Alpha
  222. qreal alpha;
  223. alpha = d->PiecewiseFunction->GetValue( pos );
  224. // returns RGBA
  225. QColor compositeValue(rgb[0], rgb[1], rgb[2], alpha);
  226. return compositeValue;
  227. }
  228. //-----------------------------------------------------------------------------
  229. int ctkVTKCompositeFunction::insertControlPoint(const ctkControlPoint& cp)
  230. {
  231. Q_UNUSED(cp);
  232. Q_D(ctkVTKCompositeFunction);
  233. int index = -1;
  234. // check piecewise
  235. if (d->PiecewiseFunction.GetPointer() == 0)
  236. {
  237. return index;
  238. }
  239. // cp: x
  240. // value = rgba
  241. /*
  242. // check color tf
  243. qreal value = cp.value().value<qreal>();
  244. const ctkNonLinearControlPoint* nonLinearCp = dynamic_cast<const ctkNonLinearControlPoint*>(&cp);
  245. if (nonLinearCp)
  246. {
  247. // TODO retrieve midpoint & sharpness
  248. index = d->PiecewiseFunction->AddPoint(
  249. cp.x(), value);
  250. }
  251. else
  252. {
  253. index = d->PiecewiseFunction->AddPoint(
  254. cp.x(), value);
  255. }*/
  256. return index;
  257. }
  258. //-----------------------------------------------------------------------------
  259. int ctkVTKCompositeFunction::insertControlPoint(qreal pos)
  260. {
  261. Q_D(ctkVTKCompositeFunction);
  262. int index = -1;
  263. // check piecewise
  264. if (d->PiecewiseFunction.GetPointer() == 0)
  265. {
  266. return index;
  267. }
  268. //check color tf
  269. if (d->ColorTransferFunction.GetPointer() == 0)
  270. {
  271. return index;
  272. }
  273. // Add color to CTF
  274. double color[3];
  275. d->ColorTransferFunction->GetColor( pos, color );
  276. int indexColor =
  277. d->ColorTransferFunction->AddRGBPoint( pos, color[0], color[1], color[2] );
  278. // Add point to piecewise
  279. #ifndef QT_NO_DEBUG
  280. int indexPiecewise =
  281. #endif
  282. d->PiecewiseFunction->AddPoint( pos, 0);
  283. // check index
  284. Q_ASSERT(indexColor == indexPiecewise);
  285. index = indexColor;
  286. return index;
  287. }
  288. //-----------------------------------------------------------------------------
  289. void ctkVTKCompositeFunction::setControlPointPos(int index, qreal pos)
  290. {
  291. Q_D(ctkVTKCompositeFunction);
  292. // update X pos in the CTF
  293. double valuesColor[6];
  294. d->ColorTransferFunction->GetNodeValue(index, valuesColor);
  295. valuesColor[0] = pos;
  296. // warning, a possible new range is not supported
  297. // SetNodeValue eventually fire the signal changed()
  298. d->ColorTransferFunction->SetNodeValue(index, valuesColor);
  299. // Update X pos in the PWF
  300. double valuesPiecewise[4];
  301. d->PiecewiseFunction->GetNodeValue(index, valuesPiecewise);
  302. // warning, a possible new range is not supported
  303. // SetNodeValue eventually fire the signal changed()
  304. valuesPiecewise[0] = pos;
  305. d->PiecewiseFunction->SetNodeValue(index, valuesPiecewise);
  306. }
  307. //-----------------------------------------------------------------------------
  308. void ctkVTKCompositeFunction::setControlPointValue(int index, const QVariant& value)
  309. {
  310. Q_D(ctkVTKCompositeFunction);
  311. // QVariant = RGBA
  312. double values[4];
  313. d->PiecewiseFunction->GetNodeValue(index, values);
  314. values[1] = value.toDouble();
  315. // setNodeValue should eventually fired the signal changed()
  316. d->PiecewiseFunction->SetNodeValue(index, values);
  317. }
  318. //-----------------------------------------------------------------------------
  319. void ctkVTKCompositeFunction::setPiecewiseFunction(vtkPiecewiseFunction* piecewiseFunction)
  320. {
  321. Q_D(ctkVTKCompositeFunction);
  322. d->PiecewiseFunction = piecewiseFunction;
  323. this->qvtkReconnect(d->PiecewiseFunction,vtkCommand::ModifiedEvent,
  324. this, SIGNAL(changed()));
  325. emit changed();
  326. }
  327. //-----------------------------------------------------------------------------
  328. void ctkVTKCompositeFunction::setColorTransferFunction(vtkColorTransferFunction* colorTransferFunction)
  329. {
  330. Q_D(ctkVTKCompositeFunction);
  331. d->ColorTransferFunction = colorTransferFunction;
  332. this->qvtkReconnect(d->ColorTransferFunction,vtkCommand::ModifiedEvent,
  333. this, SIGNAL(changed()));
  334. emit changed();
  335. }
  336. //-----------------------------------------------------------------------------
  337. vtkPiecewiseFunction* ctkVTKCompositeFunction::piecewiseFunction()const
  338. {
  339. Q_D(const ctkVTKCompositeFunction);
  340. return d->PiecewiseFunction;
  341. }
  342. //-----------------------------------------------------------------------------
  343. vtkColorTransferFunction* ctkVTKCompositeFunction::colorTransferFunction()const
  344. {
  345. Q_D(const ctkVTKCompositeFunction);
  346. return d->ColorTransferFunction;
  347. }
  348. //-----------------------------------------------------------------------------
  349. void ctkVTKCompositeFunction::removeControlPoint( qreal pos )
  350. {
  351. Q_UNUSED(pos);
  352. // TO BE IMPLEMENTED
  353. }