ctkVTKThresholdWidget.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  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. bool UseSharpness;
  41. protected:
  42. void setNodes(double nodeValues[4][4]);
  43. void setNodes(double nodeValues[][4], const int nodeCount);
  44. void setNodeValue(int index, double* nodeValue);
  45. double safeX(double value, double& previous)const;
  46. };
  47. // ----------------------------------------------------------------------------
  48. // ctkVTKThresholdWidgetPrivate methods
  49. // ----------------------------------------------------------------------------
  50. ctkVTKThresholdWidgetPrivate::ctkVTKThresholdWidgetPrivate(
  51. ctkVTKThresholdWidget& object)
  52. : q_ptr(&object)
  53. {
  54. this->PiecewiseFunction = 0;
  55. this->UserRange = false;
  56. this->UseSharpness = false;
  57. }
  58. // ----------------------------------------------------------------------------
  59. void ctkVTKThresholdWidgetPrivate::setupUi(QWidget* widget)
  60. {
  61. Q_Q(ctkVTKThresholdWidget);
  62. Q_ASSERT(q == widget);
  63. this->Ui_ctkVTKThresholdWidget::setupUi(widget);
  64. QObject::connect(this->ThresholdSliderWidget, SIGNAL(valuesChanged(double,double)),
  65. q, SLOT(setThresholdValues(double,double)));
  66. QObject::connect(this->OpacitySliderWidget, SIGNAL(valueChanged(double)),
  67. q, SLOT(setOpacity(double)));
  68. }
  69. // ----------------------------------------------------------------------------
  70. void ctkVTKThresholdWidgetPrivate::guessThreshold(double& min, double& max, double& opacity)const
  71. {
  72. min = this->ThresholdSliderWidget->minimum();
  73. max = this->ThresholdSliderWidget->maximum();
  74. opacity = 1.;
  75. if (!this->PiecewiseFunction || this->PiecewiseFunction->GetSize() == 0)
  76. {
  77. return;
  78. }
  79. int minIndex;
  80. // The min index is the point before the opacity is >0
  81. for (minIndex=0; minIndex < this->PiecewiseFunction->GetSize(); ++minIndex)
  82. {
  83. double node[4];
  84. this->PiecewiseFunction->GetNodeValue(minIndex, node);
  85. if (node[1] > 0.)
  86. {
  87. opacity = node[1];
  88. max = node[0];
  89. break;
  90. }
  91. min = node[0];
  92. }
  93. if (minIndex == this->PiecewiseFunction->GetSize())
  94. {
  95. return;
  96. }
  97. int maxIndex = minIndex + 1;
  98. for (;maxIndex < this->PiecewiseFunction->GetSize(); ++maxIndex)
  99. {
  100. double node[4];
  101. this->PiecewiseFunction->GetNodeValue(maxIndex, node);
  102. // use the max opacity
  103. opacity = std::max(opacity, node[1]);
  104. if (node[1] < opacity)
  105. {
  106. break;
  107. }
  108. max = node[0];
  109. }
  110. }
  111. // ----------------------------------------------------------------------------
  112. void ctkVTKThresholdWidgetPrivate::setRange(double min, double max)
  113. {
  114. bool wasBlocking = this->ThresholdSliderWidget->blockSignals(true);
  115. int decimals = qMax(0, -ctk::orderOfMagnitude(max - min) + 2);
  116. this->ThresholdSliderWidget->setDecimals(decimals);
  117. this->ThresholdSliderWidget->setSingleStep(pow(10., -decimals));
  118. this->ThresholdSliderWidget->setRange(min, max);
  119. this->ThresholdSliderWidget->blockSignals(wasBlocking);
  120. }
  121. // ----------------------------------------------------------------------------
  122. double ctkVTKThresholdWidgetPrivate::safeX(double value, double& previous)const
  123. {
  124. if (value < previous)
  125. {
  126. value = previous;
  127. }
  128. if (value == previous && !this->PiecewiseFunction->GetAllowDuplicateScalars())
  129. {
  130. value += 0.00000000000001;
  131. }
  132. previous = value;
  133. return value;
  134. }
  135. // ----------------------------------------------------------------------------
  136. void ctkVTKThresholdWidgetPrivate::setThreshold(double min, double max, double opacity)
  137. {
  138. Q_Q(ctkVTKThresholdWidget);
  139. if (!this->PiecewiseFunction)
  140. {
  141. return;
  142. }
  143. double range[2];
  144. this->ThresholdSliderWidget->range(range);
  145. int nodeCount = 0;
  146. if (this->UseSharpness)
  147. {
  148. // +------2
  149. // | |
  150. // 0------1 +----3
  151. nodeCount = 4;
  152. }
  153. else
  154. {
  155. // 2------3
  156. // | |
  157. // 0------1 4----5
  158. nodeCount = 6;
  159. }
  160. double (*nodes)[4] = new double[nodeCount][4];
  161. double previous = VTK_DOUBLE_MIN;
  162. // Start of the curve, always y=0
  163. int index = 0;
  164. nodes[index][0] = this->safeX(range[0], previous);
  165. nodes[index][1] = 0.;
  166. nodes[index][2] = 0.5; // midpoint
  167. nodes[index][3] = 0.; // sharpness
  168. ++index;
  169. // Starting threshold point with a sharp slope that jumps to the opacity
  170. // which is set by the next point
  171. nodes[index][0] = this->safeX(min, previous);
  172. nodes[index][1] = 0.;
  173. nodes[index][2] = this->UseSharpness ? 0. : 0.5;
  174. nodes[index][3] = this->UseSharpness ? 1. : 0.;
  175. ++index;
  176. if (!this->UseSharpness)
  177. {
  178. nodes[index][0] = this->safeX(min, previous);
  179. nodes[index][1] = opacity;
  180. nodes[index][2] = 0.5;
  181. nodes[index][3] = 0.;
  182. ++index;
  183. }
  184. // Ending threshold point with a sharp slope that jumps back to a 0 opacity
  185. nodes[index][0] = this->safeX(max, previous);;
  186. nodes[index][1] = opacity;
  187. nodes[index][2] = this->UseSharpness ? 0. : 0.5;
  188. nodes[index][3] = this->UseSharpness ? 1. : 0.;
  189. ++index;
  190. if (!this->UseSharpness)
  191. {
  192. nodes[index][0] = this->safeX(max, previous);
  193. nodes[index][1] = 0.;
  194. nodes[index][2] = 0.5;
  195. nodes[index][3] = 0.;
  196. ++index;
  197. }
  198. // End of the curve, always y = 0
  199. nodes[index][0] = this->safeX(range[1], previous);
  200. nodes[index][1] = 0.;
  201. nodes[index][2] = 0.5;
  202. nodes[index][3] = 0.;
  203. ++index;
  204. q->qvtkBlock(this->PiecewiseFunction, vtkCommand::ModifiedEvent, q);
  205. this->setNodes(nodes, nodeCount);
  206. q->qvtkUnblock(this->PiecewiseFunction, vtkCommand::ModifiedEvent, q);
  207. q->updateFromPiecewiseFunction();
  208. delete []nodes;
  209. }
  210. // ----------------------------------------------------------------------------
  211. void ctkVTKThresholdWidgetPrivate
  212. ::setNodes(double nodeValues[][4], const int nodeCount)
  213. {
  214. for(int i = 0; i < nodeCount; ++i)
  215. {
  216. int index = i;
  217. double node[4];
  218. // Search the index where to write the node
  219. for (int j = 0; j < i; ++j)
  220. {
  221. this->PiecewiseFunction->GetNodeValue(j, node);
  222. bool different = node[0] != nodeValues[j][0] ||
  223. node[1] != nodeValues[j][1] ||
  224. node[2] != nodeValues[j][2] ||
  225. node[3] != nodeValues[j][3];
  226. if (different)
  227. {
  228. index = j;
  229. break;
  230. }
  231. }
  232. if (index >= this->PiecewiseFunction->GetSize())
  233. {
  234. node[0] = VTK_DOUBLE_MAX;
  235. }
  236. else if (index == i)
  237. {
  238. this->PiecewiseFunction->GetNodeValue(index, node);
  239. }
  240. // else we already have node correctly set
  241. if (!this->UseSharpness)
  242. {
  243. // be smart in order to reduce "jumps"
  244. // Here is the intermediate steps we try to avoid:
  245. // Start
  246. // 2---3
  247. // | |
  248. // 0---1 4--5
  249. // After node1 is set:
  250. // 1 _3
  251. // |\ / |
  252. // 0---| 2 4--5
  253. // After node1 is set:
  254. // 2--3
  255. // | |
  256. // 0-----1 4--5
  257. if ((i == 1 && node[0] < nodeValues[i][0]) ||
  258. (i == 3 && node[0] < nodeValues[i][0]))
  259. {
  260. this->setNodeValue(index + 1, nodeValues[i+1]);
  261. }
  262. }
  263. this->setNodeValue(index, nodeValues[i]);
  264. }
  265. }
  266. // ----------------------------------------------------------------------------
  267. void ctkVTKThresholdWidgetPrivate::setNodeValue(int index, double* nodeValues)
  268. {
  269. if (index >= this->PiecewiseFunction->GetSize())
  270. {
  271. this->PiecewiseFunction->AddPoint(
  272. nodeValues[0], nodeValues[1], nodeValues[2], nodeValues[3]);
  273. }
  274. else
  275. {
  276. double values[4];
  277. this->PiecewiseFunction->GetNodeValue(index, values);
  278. // Updating the node will fire a modified event which can be costly
  279. // We change the node values only if there is a change.
  280. if (values[0] != nodeValues[0] ||
  281. values[1] != nodeValues[1] ||
  282. values[2] != nodeValues[2] ||
  283. values[3] != nodeValues[3])
  284. {
  285. this->PiecewiseFunction->SetNodeValue(index, nodeValues);
  286. }
  287. }
  288. }
  289. // ----------------------------------------------------------------------------
  290. // ctkVTKThresholdWidget methods
  291. // ----------------------------------------------------------------------------
  292. ctkVTKThresholdWidget::ctkVTKThresholdWidget(QWidget* parentWidget)
  293. :QWidget(parentWidget)
  294. , d_ptr(new ctkVTKThresholdWidgetPrivate(*this))
  295. {
  296. Q_D(ctkVTKThresholdWidget);
  297. d->setupUi(this);
  298. }
  299. // ----------------------------------------------------------------------------
  300. ctkVTKThresholdWidget::~ctkVTKThresholdWidget()
  301. {
  302. }
  303. // ----------------------------------------------------------------------------
  304. vtkPiecewiseFunction* ctkVTKThresholdWidget::piecewiseFunction()const
  305. {
  306. Q_D(const ctkVTKThresholdWidget);
  307. return d->PiecewiseFunction;
  308. }
  309. // ----------------------------------------------------------------------------
  310. void ctkVTKThresholdWidget
  311. ::setPiecewiseFunction(vtkPiecewiseFunction* newFunction)
  312. {
  313. Q_D(ctkVTKThresholdWidget);
  314. if (d->PiecewiseFunction == newFunction)
  315. {
  316. return;
  317. }
  318. this->qvtkReconnect(d->PiecewiseFunction, newFunction, vtkCommand::ModifiedEvent,
  319. this, SLOT(updateFromPiecewiseFunction()));
  320. d->PiecewiseFunction = newFunction;
  321. if (!d->UserRange)
  322. {
  323. double range[2] = {0., 1.};
  324. if (d->PiecewiseFunction)
  325. {
  326. d->PiecewiseFunction->GetRange(range);
  327. }
  328. d->setRange(range[0], range[1]);
  329. }
  330. if (d->PiecewiseFunction)
  331. {
  332. double min, max, value;
  333. d->guessThreshold(min, max, value);
  334. d->setThreshold(min, max, value);
  335. }
  336. }
  337. // ----------------------------------------------------------------------------
  338. void ctkVTKThresholdWidget::updateFromPiecewiseFunction()
  339. {
  340. Q_D(ctkVTKThresholdWidget);
  341. if (!d->PiecewiseFunction)
  342. {
  343. return;
  344. }
  345. double range[2];
  346. d->ThresholdSliderWidget->range(range);
  347. double minThreshold = range[0];
  348. double maxThreshold = range[1];
  349. double opacity = d->OpacitySliderWidget->value();
  350. double node[4];
  351. int minIndex = 1;
  352. if (d->PiecewiseFunction->GetSize() > minIndex)
  353. {
  354. d->PiecewiseFunction->GetNodeValue(minIndex, node);
  355. minThreshold = node[0];
  356. }
  357. int maxIndex = d->UseSharpness ? 2 : 3;
  358. if (d->PiecewiseFunction->GetSize() > maxIndex)
  359. {
  360. d->PiecewiseFunction->GetNodeValue(maxIndex, node);
  361. maxThreshold = node[0];
  362. opacity = node[1];
  363. }
  364. if (d->PiecewiseFunction->GetSize() > 3)
  365. {
  366. d->PiecewiseFunction->GetNodeValue(3, node);
  367. }
  368. bool wasBlocking = d->ThresholdSliderWidget->blockSignals(true);
  369. d->ThresholdSliderWidget->setValues(minThreshold, maxThreshold);
  370. d->ThresholdSliderWidget->blockSignals(wasBlocking);
  371. d->OpacitySliderWidget->blockSignals(true);
  372. d->OpacitySliderWidget->setValue(opacity);
  373. d->OpacitySliderWidget->blockSignals(wasBlocking);
  374. }
  375. // ----------------------------------------------------------------------------
  376. void ctkVTKThresholdWidget::setThresholdValues(double min, double max)
  377. {
  378. Q_D(ctkVTKThresholdWidget);
  379. d->setThreshold(min, max, d->OpacitySliderWidget->value());
  380. }
  381. // ----------------------------------------------------------------------------
  382. void ctkVTKThresholdWidget::thresholdValues(double* values)const
  383. {
  384. Q_D(const ctkVTKThresholdWidget);
  385. values[0] = d->ThresholdSliderWidget->minimumValue();
  386. values[1] = d->ThresholdSliderWidget->maximumValue();
  387. }
  388. // ----------------------------------------------------------------------------
  389. void ctkVTKThresholdWidget::setOpacity(double opacity)
  390. {
  391. Q_D(ctkVTKThresholdWidget);
  392. d->setThreshold(d->ThresholdSliderWidget->minimumValue(),
  393. d->ThresholdSliderWidget->maximumValue(), opacity);
  394. }
  395. // ----------------------------------------------------------------------------
  396. double ctkVTKThresholdWidget::opacity()const
  397. {
  398. Q_D(const ctkVTKThresholdWidget);
  399. return d->OpacitySliderWidget->value();
  400. }
  401. // ----------------------------------------------------------------------------
  402. void ctkVTKThresholdWidget::range(double* range)const
  403. {
  404. Q_D(const ctkVTKThresholdWidget);
  405. d->ThresholdSliderWidget->range(range);
  406. }
  407. // ----------------------------------------------------------------------------
  408. void ctkVTKThresholdWidget::setRange(double min, double max)
  409. {
  410. Q_D(ctkVTKThresholdWidget);
  411. d->UserRange = true;
  412. d->setRange(min, max);
  413. }
  414. // ----------------------------------------------------------------------------
  415. bool ctkVTKThresholdWidget::useSharpness()const
  416. {
  417. Q_D(const ctkVTKThresholdWidget);
  418. return d->UseSharpness;
  419. }
  420. // ----------------------------------------------------------------------------
  421. void ctkVTKThresholdWidget::setUseSharpness(bool use)
  422. {
  423. Q_D(ctkVTKThresholdWidget);
  424. if (use == d->UseSharpness)
  425. {
  426. return;
  427. }
  428. d->UseSharpness = use;
  429. double min, max, value;
  430. d->guessThreshold(min, max, value);
  431. d->setThreshold(min, max, value);
  432. }