ctkVTKThresholdWidget.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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 <QDebug>
  16. // CTK includes
  17. #include "ctkLogger.h"
  18. #include "ctkVTKThresholdWidget.h"
  19. #include "ctkUtils.h"
  20. #include "ui_ctkVTKThresholdWidget.h"
  21. // VTK includes
  22. #include <vtkPiecewiseFunction.h>
  23. //----------------------------------------------------------------------------
  24. static ctkLogger logger("org.commontk.visualization.vtk.widgets.ctkVTKThresholdWidget");
  25. //----------------------------------------------------------------------------
  26. class ctkVTKThresholdWidgetPrivate:
  27. public Ui_ctkVTKThresholdWidget
  28. {
  29. Q_DECLARE_PUBLIC(ctkVTKThresholdWidget);
  30. protected:
  31. ctkVTKThresholdWidget* const q_ptr;
  32. public:
  33. ctkVTKThresholdWidgetPrivate(ctkVTKThresholdWidget& object);
  34. void setupUi(QWidget* widget);
  35. void setThreshold(double min, double max, double opacity);
  36. void setRange(double min, double max);
  37. void guessThreshold(double& min, double& max, double& opacity)const;
  38. vtkPiecewiseFunction* PiecewiseFunction;
  39. bool UserRange;
  40. protected:
  41. void setNodes(double nodeValues[4][4]);
  42. void setNodeValue(int index, double* nodeValue);
  43. };
  44. // ----------------------------------------------------------------------------
  45. // ctkVTKThresholdWidgetPrivate methods
  46. // ----------------------------------------------------------------------------
  47. ctkVTKThresholdWidgetPrivate::ctkVTKThresholdWidgetPrivate(
  48. ctkVTKThresholdWidget& object)
  49. : q_ptr(&object)
  50. {
  51. this->PiecewiseFunction = 0;
  52. this->UserRange = false;
  53. }
  54. // ----------------------------------------------------------------------------
  55. void ctkVTKThresholdWidgetPrivate::setupUi(QWidget* widget)
  56. {
  57. Q_Q(ctkVTKThresholdWidget);
  58. Q_ASSERT(q == widget);
  59. this->Ui_ctkVTKThresholdWidget::setupUi(widget);
  60. QObject::connect(this->ThresholdSliderWidget, SIGNAL(valuesChanged(double,double)),
  61. q, SLOT(setThresholdValues(double,double)));
  62. QObject::connect(this->OpacitySliderWidget, SIGNAL(valueChanged(double)),
  63. q, SLOT(setOpacity(double)));
  64. }
  65. // ----------------------------------------------------------------------------
  66. void ctkVTKThresholdWidgetPrivate::guessThreshold(double& min, double& max, double& opacity)const
  67. {
  68. min = this->ThresholdSliderWidget->minimum();
  69. max = this->ThresholdSliderWidget->maximum();
  70. opacity = 1.;
  71. if (!this->PiecewiseFunction || this->PiecewiseFunction->GetSize() == 0)
  72. {
  73. return;
  74. }
  75. int minIndex;
  76. for (minIndex=0; minIndex < this->PiecewiseFunction->GetSize(); ++minIndex)
  77. {
  78. double node[4];
  79. this->PiecewiseFunction->GetNodeValue(minIndex, node);
  80. if (node[1] > 0.)
  81. {
  82. min = node[0];
  83. opacity = node[1];
  84. break;
  85. }
  86. }
  87. if (minIndex == this->PiecewiseFunction->GetSize())
  88. {
  89. return;
  90. }
  91. int maxIndex;
  92. for (maxIndex = minIndex + 1;
  93. maxIndex < this->PiecewiseFunction->GetSize();
  94. ++maxIndex)
  95. {
  96. double node[4];
  97. this->PiecewiseFunction->GetNodeValue(maxIndex, node);
  98. // average the opacities
  99. opacity += node[1];
  100. if (node[1] == 0.)
  101. {
  102. max = node[0];
  103. opacity /= maxIndex - minIndex + 1;
  104. break;
  105. }
  106. }
  107. // couldn't find the upper threshold value, use the upper range
  108. if (maxIndex == this->PiecewiseFunction->GetSize())
  109. {
  110. opacity /= maxIndex - minIndex;
  111. }
  112. }
  113. // ----------------------------------------------------------------------------
  114. void ctkVTKThresholdWidgetPrivate::setRange(double min, double max)
  115. {
  116. bool wasBlocking = this->ThresholdSliderWidget->blockSignals(true);
  117. int decimals = qMax(0, -ctk::orderOfMagnitude(max - min) + 2);
  118. this->ThresholdSliderWidget->setDecimals(decimals);
  119. this->ThresholdSliderWidget->setSingleStep(pow(10., -decimals));
  120. this->ThresholdSliderWidget->setRange(min, max);
  121. this->ThresholdSliderWidget->blockSignals(wasBlocking);
  122. }
  123. // ----------------------------------------------------------------------------
  124. void ctkVTKThresholdWidgetPrivate::setThreshold(double min, double max, double opacity)
  125. {
  126. Q_Q(ctkVTKThresholdWidget);
  127. if (!this->PiecewiseFunction)
  128. {
  129. return;
  130. }
  131. double range[2];
  132. this->ThresholdSliderWidget->range(range);
  133. // Start of the curve, always y=0
  134. double nodes[4][4];
  135. nodes[0][0] = range[0];
  136. nodes[0][1] = 0.;
  137. nodes[0][2] = 0.5; // midpoint
  138. nodes[0][3] = 0.; // sharpness
  139. // Starting threshold point with a sharp slope that jumps to the opacity
  140. // which is set by the next point
  141. nodes[1][0] = min +
  142. ((min == nodes[0][0] && !this->PiecewiseFunction->GetAllowDuplicateScalars()) ?
  143. 0.00000000000001 : 0.);
  144. nodes[1][1] = 0.;
  145. nodes[1][2] = 0.; // jumps directly
  146. nodes[1][3] = 1.; // sharp
  147. // Ending threshold point with a sharp slope that jumps back to a 0 opacity
  148. nodes[2][0] = max +
  149. ((max == nodes[1][0] && !this->PiecewiseFunction->GetAllowDuplicateScalars()) ?
  150. 0.00000000000001 : 0.);
  151. nodes[2][1] = opacity;
  152. nodes[2][2] = 0.;
  153. nodes[2][3] = 1.;
  154. // End of the curve, always y = 0
  155. nodes[3][0] = range[1] +
  156. ((range[1] == nodes[2][0] && !this->PiecewiseFunction->GetAllowDuplicateScalars()) ?
  157. 0.00000000000001 : 0.);
  158. nodes[3][1] = 0.;
  159. nodes[3][2] = 0.5;
  160. nodes[3][3] = 0.;
  161. q->qvtkBlock(this->PiecewiseFunction, vtkCommand::ModifiedEvent, q);
  162. this->setNodes(nodes);
  163. q->qvtkUnblock(this->PiecewiseFunction, vtkCommand::ModifiedEvent, q);
  164. q->updateFromPiecewiseFunction();
  165. }
  166. // ----------------------------------------------------------------------------
  167. void ctkVTKThresholdWidgetPrivate::setNodes(double nodeValues[4][4])
  168. {
  169. double lastX = VTK_DOUBLE_MIN;
  170. double minX = nodeValues[0][0];
  171. for(int i = 0; i < 4; ++i)
  172. {
  173. int index = this->PiecewiseFunction->GetSize();
  174. bool alreadyEqual = false;
  175. // search the node index to modify
  176. for (int j = 0; j < this->PiecewiseFunction->GetSize(); ++j)
  177. {
  178. double node[4];
  179. this->PiecewiseFunction->GetNodeValue(j, node);
  180. if (node[0] < minX || node[0] > lastX)
  181. {
  182. index = j;
  183. break;
  184. }
  185. else if (node[0] == lastX)
  186. {
  187. if (alreadyEqual)
  188. {
  189. index = j;
  190. break;
  191. }
  192. alreadyEqual = true;
  193. }
  194. }
  195. this->setNodeValue(index, nodeValues[i]);
  196. lastX = nodeValues[i][0];
  197. }
  198. }
  199. // ----------------------------------------------------------------------------
  200. void ctkVTKThresholdWidgetPrivate::setNodeValue(int index, double* nodeValues)
  201. {
  202. if (this->PiecewiseFunction->GetSize() <= index)
  203. {
  204. this->PiecewiseFunction->AddPoint(
  205. nodeValues[0], nodeValues[1], nodeValues[2], nodeValues[3]);
  206. }
  207. else
  208. {
  209. this->PiecewiseFunction->SetNodeValue(index, nodeValues);
  210. }
  211. }
  212. // ----------------------------------------------------------------------------
  213. // ctkVTKThresholdWidget methods
  214. // ----------------------------------------------------------------------------
  215. ctkVTKThresholdWidget::ctkVTKThresholdWidget(QWidget* parentWidget)
  216. :QWidget(parentWidget)
  217. , d_ptr(new ctkVTKThresholdWidgetPrivate(*this))
  218. {
  219. Q_D(ctkVTKThresholdWidget);
  220. d->setupUi(this);
  221. }
  222. // ----------------------------------------------------------------------------
  223. ctkVTKThresholdWidget::~ctkVTKThresholdWidget()
  224. {
  225. }
  226. // ----------------------------------------------------------------------------
  227. vtkPiecewiseFunction* ctkVTKThresholdWidget::piecewiseFunction()const
  228. {
  229. Q_D(const ctkVTKThresholdWidget);
  230. return d->PiecewiseFunction;
  231. }
  232. // ----------------------------------------------------------------------------
  233. void ctkVTKThresholdWidget
  234. ::setPiecewiseFunction(vtkPiecewiseFunction* newFunction)
  235. {
  236. Q_D(ctkVTKThresholdWidget);
  237. if (d->PiecewiseFunction == newFunction)
  238. {
  239. return;
  240. }
  241. this->qvtkReconnect(d->PiecewiseFunction, newFunction, vtkCommand::ModifiedEvent,
  242. this, SLOT(updateFromPiecewiseFunction()));
  243. d->PiecewiseFunction = newFunction;
  244. if (!d->UserRange)
  245. {
  246. double range[2] = {0., 1.};
  247. if (d->PiecewiseFunction)
  248. {
  249. d->PiecewiseFunction->GetRange(range);
  250. }
  251. d->setRange(range[0], range[1]);
  252. }
  253. if (d->PiecewiseFunction)
  254. {
  255. double min, max, value;
  256. d->guessThreshold(min, max, value);
  257. d->setThreshold(min, max, value);
  258. }
  259. }
  260. // ----------------------------------------------------------------------------
  261. void ctkVTKThresholdWidget::updateFromPiecewiseFunction()
  262. {
  263. Q_D(ctkVTKThresholdWidget);
  264. if (!d->PiecewiseFunction)
  265. {
  266. return;
  267. }
  268. double range[2];
  269. d->ThresholdSliderWidget->range(range);
  270. double minThreshold = range[0];
  271. double maxThreshold = range[1];
  272. double opacity = d->OpacitySliderWidget->value();
  273. double node[4];
  274. if (d->PiecewiseFunction->GetSize() > 1)
  275. {
  276. d->PiecewiseFunction->GetNodeValue(1, node);
  277. minThreshold = node[0];
  278. }
  279. if (d->PiecewiseFunction->GetSize() > 2)
  280. {
  281. d->PiecewiseFunction->GetNodeValue(2, node);
  282. maxThreshold = node[0];
  283. opacity = node[1];
  284. }
  285. if (d->PiecewiseFunction->GetSize() > 3)
  286. {
  287. d->PiecewiseFunction->GetNodeValue(3, node);
  288. }
  289. bool wasBlocking = d->ThresholdSliderWidget->blockSignals(true);
  290. d->ThresholdSliderWidget->setValues(minThreshold, maxThreshold);
  291. d->ThresholdSliderWidget->blockSignals(wasBlocking);
  292. d->OpacitySliderWidget->blockSignals(true);
  293. d->OpacitySliderWidget->setValue(opacity);
  294. d->OpacitySliderWidget->blockSignals(wasBlocking);
  295. }
  296. // ----------------------------------------------------------------------------
  297. void ctkVTKThresholdWidget::setThresholdValues(double min, double max)
  298. {
  299. Q_D(ctkVTKThresholdWidget);
  300. d->setThreshold(min, max, d->OpacitySliderWidget->value());
  301. }
  302. // ----------------------------------------------------------------------------
  303. void ctkVTKThresholdWidget::thresholdValues(double* values)const
  304. {
  305. Q_D(const ctkVTKThresholdWidget);
  306. values[0] = d->ThresholdSliderWidget->minimumValue();
  307. values[1] = d->ThresholdSliderWidget->maximumValue();
  308. }
  309. // ----------------------------------------------------------------------------
  310. void ctkVTKThresholdWidget::setOpacity(double opacity)
  311. {
  312. Q_D(ctkVTKThresholdWidget);
  313. d->setThreshold(d->ThresholdSliderWidget->minimumValue(),
  314. d->ThresholdSliderWidget->maximumValue(), opacity);
  315. }
  316. // ----------------------------------------------------------------------------
  317. double ctkVTKThresholdWidget::opacity()const
  318. {
  319. Q_D(const ctkVTKThresholdWidget);
  320. return d->OpacitySliderWidget->value();
  321. }
  322. // ----------------------------------------------------------------------------
  323. void ctkVTKThresholdWidget::range(double* range)const
  324. {
  325. Q_D(const ctkVTKThresholdWidget);
  326. d->ThresholdSliderWidget->range(range);
  327. }
  328. // ----------------------------------------------------------------------------
  329. void ctkVTKThresholdWidget::setRange(double min, double max)
  330. {
  331. Q_D(ctkVTKThresholdWidget);
  332. d->UserRange = true;
  333. d->setRange(min, max);
  334. }