ccColorFromScalarDlg.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: CloudCompare project #
  15. //# #
  16. //##########################################################################
  17. #include "ccColorFromScalarDlg.h"
  18. //local
  19. #include "ccConsole.h"
  20. #include "ccHistogramWindow.h"
  21. //qCC_db
  22. #include <ccColorScale.h>
  23. #include <ccGenericGLDisplay.h>
  24. #include <ccHObjectCaster.h>
  25. #include <ccPointCloud.h>
  26. //Qt
  27. #include <QPushButton>
  28. //ui
  29. #include <ui_colorFromScalarDlg.h>
  30. //system
  31. #include <cassert>
  32. #include <cstring>
  33. ccColorFromScalarDlg::ccColorFromScalarDlg(QWidget* parent, ccPointCloud* pointCloud)
  34. : QDialog(parent, Qt::Tool)
  35. , m_cloud(pointCloud)
  36. , m_systemInvalid(false)
  37. , m_ui(new Ui::ColorFromScalarDialog)
  38. {
  39. m_ui->setupUi(this);
  40. //populate boxes
  41. m_boxes_min[0] = m_ui->minInputSpinBoxR;
  42. m_boxes_max[0] = m_ui->maxInputSpinBoxR;
  43. m_boxes_min[1] = m_ui->minInputSpinBoxG;
  44. m_boxes_max[1] = m_ui->maxInputSpinBoxG;
  45. m_boxes_min[2] = m_ui->minInputSpinBoxB;
  46. m_boxes_max[2] = m_ui->maxInputSpinBoxB;
  47. m_boxes_min[3] = m_ui->minInputSpinBoxA;
  48. m_boxes_max[3] = m_ui->maxInputSpinBoxA;
  49. //populate combo boxes
  50. m_combos[0] = m_ui->channelComboR;
  51. m_combos[1] = m_ui->channelComboG;
  52. m_combos[2] = m_ui->channelComboB;
  53. m_combos[3] = m_ui->channelComboA;
  54. //populate labels
  55. m_labels_min[0] = m_ui->MinLabelR;
  56. m_labels_min[1] = m_ui->MinLabelG;
  57. m_labels_min[2] = m_ui->MinLabelB;
  58. m_labels_min[3] = m_ui->MinLabelA;
  59. m_labels_max[0] = m_ui->MaxLabelR;
  60. m_labels_max[1] = m_ui->MaxLabelG;
  61. m_labels_max[2] = m_ui->MaxLabelB;
  62. m_labels_max[3] = m_ui->MaxLabelA;
  63. m_reverse[0] = m_ui->reverseR;
  64. m_reverse[1] = m_ui->reverseG;
  65. m_reverse[2] = m_ui->reverseB;
  66. m_reverse[3] = m_ui->reverseA;
  67. m_ui->fixA->setChecked(true); //set alpha fixed to checked
  68. //create histograms
  69. QFrame* histoFrame[c_channelCount] = { m_ui->histoFrameR, m_ui->histoFrameG, m_ui->histoFrameB, m_ui->histoFrameA };
  70. for (unsigned i = 0; i < c_channelCount; i++)
  71. {
  72. m_histograms[i] = new ccHistogramWindow(this);
  73. m_histograms[i]->setRefreshAfterResize(false);
  74. auto layout = new QHBoxLayout;
  75. layout->setContentsMargins(0, 0, 0, 0);
  76. layout->addWidget(m_histograms[i]);
  77. histoFrame[i]->setLayout(layout);
  78. }
  79. //initialise colour scales
  80. for (unsigned i = 0; i < c_channelCount; i++)
  81. {
  82. m_colors[i] = ccColorScale::Shared(new ccColorScale(QString::asprintf("%d", i)));
  83. }
  84. if (m_cloud->getNumberOfScalarFields() > 0)
  85. {
  86. if (m_cloud->getCurrentDisplayedScalarFieldIndex() == -1)
  87. {
  88. m_cloud->setCurrentDisplayedScalarField(0);
  89. }
  90. ccScalarField* sf = static_cast<ccScalarField*>(m_cloud->getCurrentDisplayedScalarField());
  91. if (!sf) // I had this happen 1 time during testing but could never replicate
  92. {
  93. assert(false);
  94. ccLog::Error("[ccColorFromScalarDlg] Get current scalar field failed!");
  95. m_systemInvalid = true;
  96. disableAllButCancel();
  97. }
  98. else
  99. {
  100. m_storedOrigColorScale = sf->getColorScale();
  101. m_storedOrigSatRange = sf->saturationRange();
  102. m_storedOrigDisplayRange = sf->displayRange();
  103. for (unsigned i = 0; i < c_channelCount; i++)
  104. {
  105. m_scalars[i] = nullptr;
  106. m_prevFixed[i] = true;
  107. m_combos[i]->clear();
  108. for (unsigned int s = 0; s < m_cloud->getNumberOfScalarFields(); s++)
  109. {
  110. m_combos[i]->addItem(QString::fromStdString(m_cloud->getScalarFieldName(s)));
  111. }
  112. m_combos[i]->setCurrentIndex(m_cloud->getCurrentDisplayedScalarFieldIndex());
  113. }
  114. updateColormaps();
  115. //initialise histograms
  116. m_prevFixed[c_channelCount - 1] = false;
  117. updateChannel(0); //init first histogram
  118. for (unsigned i = 1; i < c_channelCount; i++) //copy data from this histogram into the next ones
  119. {
  120. m_scalars[i] = sf;
  121. setDefaultSatValuePerChannel(i);
  122. m_histograms[i]->fromBinArray(m_histograms[0]->histoValues(), m_histograms[0]->minVal(), m_histograms[0]->maxVal());
  123. updateHistogram(i);
  124. }
  125. sf->setColorScale(m_colors[c_channelCount - 1]); //set grey colour ramp to start with
  126. m_cloud->redrawDisplay();
  127. }
  128. }
  129. else
  130. {
  131. ccLog::Error("[ccColorFromScalarDlg] Current cloud has no scalar fields!");
  132. m_systemInvalid = true;
  133. disableAllButCancel();
  134. }
  135. //connect GUI elements
  136. connect(m_ui->channelComboR, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccColorFromScalarDlg::onChannelChangedR);
  137. connect(m_ui->channelComboG, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccColorFromScalarDlg::onChannelChangedG);
  138. connect(m_ui->channelComboB, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccColorFromScalarDlg::onChannelChangedB);
  139. connect(m_ui->channelComboA, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccColorFromScalarDlg::onChannelChangedA);
  140. connect(m_ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &ccColorFromScalarDlg::onApply);
  141. connect(m_ui->minInputSpinBoxR, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::minSpinChangedR);
  142. connect(m_ui->maxInputSpinBoxR, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::maxSpinChangedR);
  143. connect(m_ui->minInputSpinBoxG, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::minSpinChangedG);
  144. connect(m_ui->maxInputSpinBoxG, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::maxSpinChangedG);
  145. connect(m_ui->minInputSpinBoxB, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::minSpinChangedB);
  146. connect(m_ui->maxInputSpinBoxB, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::maxSpinChangedB);
  147. connect(m_ui->minInputSpinBoxA, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::minSpinChangedA);
  148. connect(m_ui->maxInputSpinBoxA, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccColorFromScalarDlg::maxSpinChangedA);
  149. connect(m_ui->reverseR, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleColors);
  150. connect(m_ui->reverseG, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleColors);
  151. connect(m_ui->reverseB, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleColors);
  152. connect(m_ui->reverseA, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleColors);
  153. connect(m_ui->toggleHSV, &QRadioButton::toggled, this, &ccColorFromScalarDlg::toggleColorMode);
  154. connect(m_ui->toggleRGB, &QRadioButton::toggled, this, &ccColorFromScalarDlg::toggleColorMode);
  155. connect(m_ui->fixR, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleFixedR);
  156. connect(m_ui->fixG, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleFixedG);
  157. connect(m_ui->fixB, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleFixedB);
  158. connect(m_ui->fixA, &QCheckBox::stateChanged, this, &ccColorFromScalarDlg::toggleFixedA);
  159. //connect histogram events
  160. connect(m_histograms[0], &ccHistogramWindow::sfMinSatValChanged, this, &ccColorFromScalarDlg::minChangedR);
  161. connect(m_histograms[0], &ccHistogramWindow::sfMaxSatValChanged, this, &ccColorFromScalarDlg::maxChangedR);
  162. connect(m_histograms[1], &ccHistogramWindow::sfMinSatValChanged, this, &ccColorFromScalarDlg::minChangedG);
  163. connect(m_histograms[1], &ccHistogramWindow::sfMaxSatValChanged, this, &ccColorFromScalarDlg::maxChangedG);
  164. connect(m_histograms[2], &ccHistogramWindow::sfMinSatValChanged, this, &ccColorFromScalarDlg::minChangedB);
  165. connect(m_histograms[2], &ccHistogramWindow::sfMaxSatValChanged, this, &ccColorFromScalarDlg::maxChangedB);
  166. connect(m_histograms[3], &ccHistogramWindow::sfMinSatValChanged, this, &ccColorFromScalarDlg::minChangedA);
  167. connect(m_histograms[3], &ccHistogramWindow::sfMaxSatValChanged, this, &ccColorFromScalarDlg::maxChangedA);
  168. for (int i = 1; i < c_channelCount; ++i)
  169. {
  170. updateChannel( i );
  171. }
  172. }
  173. ccColorFromScalarDlg::~ccColorFromScalarDlg()
  174. {
  175. if (!m_systemInvalid)
  176. {
  177. ccScalarField* sf = static_cast<ccScalarField*>(m_cloud->getCurrentDisplayedScalarField());
  178. if (sf)
  179. {
  180. sf->setColorScale(m_storedOrigColorScale);
  181. sf->setSaturationStart(m_storedOrigSatRange.min());
  182. sf->setSaturationStop(m_storedOrigSatRange.max());
  183. sf->setMinDisplayed(m_storedOrigDisplayRange.min());
  184. sf->setMaxDisplayed(m_storedOrigDisplayRange.max());
  185. m_cloud->redrawDisplay();
  186. }
  187. }
  188. delete m_ui;
  189. }
  190. void ccColorFromScalarDlg::updateColormaps()
  191. {
  192. if (!m_systemInvalid)
  193. {
  194. //check for reversed
  195. bool reversed[c_channelCount] = { m_ui->reverseR->isChecked(), m_ui->reverseG->isChecked(), m_ui->reverseB->isChecked(), m_ui->reverseA->isChecked() };
  196. //create colourmaps for RGB
  197. if (m_ui->toggleRGB->isChecked())
  198. {
  199. //update labels
  200. m_ui->mRedLabel->setText(QStringLiteral("Red"));
  201. m_ui->mGreenLabel->setText(QStringLiteral("Green"));
  202. m_ui->mBlueLabel->setText(QStringLiteral("Blue"));
  203. m_ui->mAlphaLabel->setText(QStringLiteral("Alpha"));
  204. //populate colour ramps
  205. Qt::GlobalColor start_colors[c_channelCount] = { Qt::black , Qt::black , Qt::black , Qt::black };
  206. Qt::GlobalColor end_colors[c_channelCount] = { Qt::red , Qt::green , Qt::blue , Qt::white };
  207. for (unsigned i = 0; i < c_channelCount; i++)
  208. {
  209. m_colors[i]->clear();
  210. if (reversed[i]) //flip
  211. {
  212. m_colors[i]->insert(ccColorScaleElement(0.0, end_colors[i]));
  213. m_colors[i]->insert(ccColorScaleElement(1.0, start_colors[i]));
  214. }
  215. else
  216. {
  217. m_colors[i]->insert(ccColorScaleElement(0.0, start_colors[i]));
  218. m_colors[i]->insert(ccColorScaleElement(1.0, end_colors[i]));
  219. }
  220. m_colors[i]->update();
  221. }
  222. }
  223. else //create colourmaps for HSV
  224. {
  225. //update labels
  226. m_ui->mRedLabel->setText(QStringLiteral("Hue"));
  227. m_ui->mGreenLabel->setText(QStringLiteral("Sat"));
  228. m_ui->mBlueLabel->setText(QStringLiteral("Value"));
  229. m_ui->mAlphaLabel->setText(QStringLiteral("Alpha"));
  230. //populate colour ramps
  231. Qt::GlobalColor start_colors[c_channelCount] = { Qt::black , Qt::gray , Qt::black , Qt::black };
  232. Qt::GlobalColor end_colors[c_channelCount] = { Qt::red , Qt::green , Qt::white , Qt::white };
  233. for (unsigned i = 0; i < c_channelCount; i++)
  234. {
  235. m_colors[i]->clear();
  236. if (reversed[i]) //flip
  237. {
  238. m_colors[i]->insert(ccColorScaleElement(0.0, end_colors[i]));
  239. m_colors[i]->insert(ccColorScaleElement(1.0, start_colors[i]));
  240. }
  241. else
  242. {
  243. m_colors[i]->insert(ccColorScaleElement(0.0, start_colors[i]));
  244. m_colors[i]->insert(ccColorScaleElement(1.0, end_colors[i]));
  245. }
  246. m_colors[i]->update();
  247. }
  248. //overwrite first colourmap with hue rainbow
  249. int hue;
  250. m_colors[0]->clear();
  251. ccColor::Rgb col = ccColor::Convert::hsv2rgb(360.0f, 1.0f, 1.0f);
  252. m_colors[0]->insert(ccColorScaleElement(1.0, QColor(col.r, col.g, col.b, 255)));
  253. for (unsigned i = 0; i < 360; i += 2)
  254. {
  255. //calculate hue value
  256. if (reversed[0])
  257. {
  258. hue = 360 - i;
  259. }
  260. else
  261. {
  262. hue = i;
  263. }
  264. //calculate colour
  265. col = ccColor::Convert::hsv2rgb(hue, 1.0f, 1.0f);
  266. //add stop
  267. m_colors[0]->insert(ccColorScaleElement(static_cast<double>(i) / 360.0, QColor(col.r, col.g, col.b, 255)));
  268. }
  269. m_colors[0]->update();
  270. }
  271. }
  272. }
  273. void ccColorFromScalarDlg::toggleColors(int state)
  274. {
  275. if (!m_systemInvalid)
  276. {
  277. //update colourmaps
  278. updateColormaps();
  279. //refresh histograms
  280. refreshDisplay();
  281. }
  282. }
  283. void ccColorFromScalarDlg::toggleColorMode(bool state)
  284. {
  285. if (!m_systemInvalid)
  286. {
  287. //update colourmaps
  288. updateColormaps();
  289. refreshDisplay();
  290. }
  291. }
  292. // update/redraw histograms but don't reset postion of UI elements/sliders etc.
  293. void ccColorFromScalarDlg::refreshDisplay()
  294. {
  295. if (!m_systemInvalid)
  296. {
  297. // refresh histograms
  298. for (int i = 0; i < c_channelCount; i++)
  299. {
  300. updateHistogram(i);
  301. }
  302. }
  303. }
  304. void ccColorFromScalarDlg::updateHistogram(int n)
  305. {
  306. if (!m_systemInvalid)
  307. {
  308. if (n >= c_channelCount || n < 0)
  309. {
  310. ccLog::Error("[ccColorFromScalarDlg] updateHistogram called with an invalid channel index");
  311. return;
  312. }
  313. //first check if fixed or not and enable disable ui features based on this
  314. bool fixed[c_channelCount] = { m_ui->fixR->isChecked(), m_ui->fixG->isChecked(), m_ui->fixB->isChecked(), m_ui->fixA->isChecked() };
  315. m_histograms[n]->setEnabled(!fixed[n]);
  316. m_combos[n]->setEnabled(!fixed[n]);
  317. m_boxes_max[n]->setEnabled(!fixed[n]);
  318. m_labels_max[n]->setEnabled(!fixed[n]);
  319. m_reverse[n]->setEnabled(!fixed[n]);
  320. if (fixed[n]) //this channel is/has been fixed
  321. {
  322. if (fixed[n] != m_prevFixed[n])
  323. {
  324. m_labels_min[n]->setText(" Value:");
  325. m_boxes_min[n]->setMaximum(255.0);
  326. m_boxes_min[n]->setMinimum(0.0);
  327. m_boxes_max[n]->setMaximum(255.0);
  328. m_boxes_max[n]->setMinimum(0.0);
  329. m_boxes_max[n]->setValue(200.0);
  330. m_boxes_min[n]->setValue(200.0);
  331. m_boxes_min[n]->setSingleStep(1.0);
  332. m_boxes_max[n]->setSingleStep(1.0);
  333. //edge case for HSV values (0 - 360)
  334. if (n == 0 && m_ui->toggleHSV->isChecked())
  335. {
  336. m_boxes_min[n]->setMaximum(360);
  337. }
  338. }
  339. //and make histogram grey
  340. m_histograms[n]->clear();
  341. m_histograms[n]->setSFInteractionMode(ccHistogramWindow::SFInteractionMode::None); //disable interactivity
  342. m_histograms[n]->setAxisLabels("", "");
  343. m_histograms[n]->setAxisDisplayOption(ccHistogramWindow::AxisDisplayOption::None); //only display XAxis
  344. m_histograms[n]->refresh();
  345. m_histograms[n]->replot();
  346. }
  347. else
  348. {
  349. if (fixed[n] != m_prevFixed[n])
  350. {
  351. setDefaultSatValuePerChannel(n); //update slider positions
  352. m_labels_min[n]->setText("Minimum:"); //ensure label text is correct
  353. }
  354. //set scalar field
  355. m_scalars[n]->setColorScale(m_colors[n]);
  356. m_scalars[n]->setSaturationStart(m_boxes_min[n]->value());
  357. m_scalars[n]->setSaturationStop(m_boxes_max[n]->value());
  358. m_histograms[n]->setSFInteractionMode(ccHistogramWindow::SFInteractionMode::SaturationRange); //disable interactivity
  359. m_histograms[n]->setAxisLabels("", "");
  360. m_histograms[n]->setAxisDisplayOption(ccHistogramWindow::AxisDisplayOption::XAxis); //only display XAxis
  361. m_histograms[n]->refresh();
  362. }
  363. m_prevFixed[n] = fixed[n];
  364. }
  365. }
  366. void ccColorFromScalarDlg::updateSpinBoxLimits(int n)
  367. {
  368. if (!m_systemInvalid)
  369. {
  370. if (n >= c_channelCount || n < 0)
  371. {
  372. ccLog::Error("[ccColorFromScalarDlg] updateSpinBoxLimits called with an invalid channel index");
  373. return;
  374. }
  375. bool fixed[c_channelCount] = { m_ui->fixR->isChecked(), m_ui->fixG->isChecked(), m_ui->fixB->isChecked(), m_ui->fixA->isChecked() };
  376. if (fixed[n])
  377. {
  378. return;
  379. }
  380. ccScalarField* sf = static_cast<ccScalarField*>(m_cloud->getScalarField(m_combos[n]->currentIndex()));
  381. if (sf)
  382. {
  383. m_minSat[n] = sf->getMin();
  384. m_maxSat[n] = sf->getMax();
  385. double singleStepSize = (m_maxSat[n] - m_minSat[n]) / 100.0;
  386. if (singleStepSize < 0.01)
  387. {
  388. singleStepSize = 0.01;
  389. }
  390. m_boxes_min[n]->setMinimum(m_minSat[n]);
  391. m_boxes_min[n]->setMaximum(m_maxSat[n]);
  392. m_boxes_min[n]->setSingleStep(singleStepSize);
  393. m_boxes_max[n]->setMinimum(m_minSat[n]);
  394. m_boxes_max[n]->setMaximum(m_maxSat[n]);
  395. m_boxes_max[n]->setSingleStep(singleStepSize);
  396. m_boxes_max[n]->setCorrectionMode(QAbstractSpinBox::CorrectionMode::CorrectToNearestValue);
  397. }
  398. }
  399. }
  400. void ccColorFromScalarDlg::updateChannel(int n)
  401. {
  402. if (!m_systemInvalid)
  403. {
  404. if (n >= c_channelCount || n < 0)
  405. {
  406. ccLog::Error("[ccColorFromScalarDlg] updateChannel called with an invalid channel index");
  407. return;
  408. }
  409. ccScalarField* sf = static_cast<ccScalarField*>(m_cloud->getScalarField(m_combos[n]->currentIndex()));
  410. if (sf)
  411. {
  412. m_scalars[n] = sf;
  413. setDefaultSatValuePerChannel(n);
  414. m_histograms[n]->clear(); //clear last histogram
  415. m_histograms[n]->fromSF(m_scalars[n], 255, false, true); //generate new one
  416. updateHistogram(n); //update plotting etc.
  417. }
  418. }
  419. }
  420. void ccColorFromScalarDlg::setDefaultSatValuePerChannel(int n)
  421. {
  422. if (!m_systemInvalid)
  423. {
  424. if (n >= c_channelCount || n < 0)
  425. {
  426. ccLog::Error("[ccColorFromScalarDlg] setDefaultSatValuePerChannel called with an invalid channel index");
  427. return;
  428. }
  429. //set default stretch (n.b. this is a cheap hack to avoid calculating percentiles [by assuming uniform data distribution])
  430. m_scalars[n]->setColorScale(m_colors[n]);
  431. m_minSat[n] = m_scalars[n]->getMin();
  432. m_maxSat[n] = m_scalars[n]->getMax();
  433. updateSpinBoxLimits(n);
  434. ScalarType range = m_maxSat[n] - m_minSat[n];
  435. m_histograms[n]->setMinSatValue(m_minSat[n] + 0.1 * range);
  436. m_boxes_min[n]->setValue(m_minSat[n] + 0.1 * range);
  437. m_histograms[n]->setMaxSatValue(m_maxSat[n] - 0.1 * range);
  438. m_boxes_max[n]->setValue(m_maxSat[n] - 0.1 * range);
  439. }
  440. }
  441. void ccColorFromScalarDlg::resizeEvent(QResizeEvent* event)
  442. {
  443. refreshDisplay();
  444. }
  445. //mapping ranges changed
  446. void ccColorFromScalarDlg::minChanged(int n, double val, bool slider)
  447. {
  448. if (n >= c_channelCount || n < 0)
  449. {
  450. ccLog::Error("[ccColorFromScalarDlg] minChanged called with an invalid channel index");
  451. return;
  452. }
  453. if (val <= m_maxSat[n]) //valid value?
  454. {
  455. m_scalars[n]->setColorScale(m_colors[n]);
  456. m_minSat[n] = val;
  457. if (slider) //change was made with the slider
  458. {
  459. m_boxes_min[n]->setValue(val);
  460. }
  461. else //change was made with text box
  462. {
  463. m_histograms[n]->setMinSatValue(val);
  464. }
  465. }
  466. else
  467. {
  468. //ccLog::Warning(QString("minChanged Channel %1 failed New min > max, val = %2, maxval = %3").arg(n).arg(val).arg(m_maxSat[n]));
  469. }
  470. }
  471. void ccColorFromScalarDlg::maxChanged(int n, double val, bool slider)
  472. {
  473. if (n >= c_channelCount || n < 0)
  474. {
  475. ccLog::Error("[ccColorFromScalarDlg] maxChanged called with an invalid channel index");
  476. return;
  477. }
  478. if (val >= m_minSat[n]) //valid value?
  479. {
  480. m_scalars[n]->setColorScale(m_colors[n]);
  481. m_maxSat[n] = val;
  482. if (slider) //change was made with the slider
  483. {
  484. m_boxes_max[n]->setValue(val);
  485. }
  486. else //change was made with text box
  487. {
  488. m_histograms[n]->setMaxSatValue(val);
  489. }
  490. }
  491. else
  492. {
  493. //ccLog::Warning(QString("maxChanged Channel %1 failed New max < min, val = %2, minval = %3").arg(n).arg(val).arg(m_minSat[n]));
  494. }
  495. }
  496. void ccColorFromScalarDlg::onApply()
  497. {
  498. if (!m_systemInvalid)
  499. {
  500. if (!m_cloud->hasColors())
  501. {
  502. if (!m_cloud->resizeTheRGBTable(false))
  503. {
  504. ccLog::Error(tr("Not enough memory"));
  505. return;
  506. }
  507. }
  508. //which maps to flip?
  509. bool reversed[c_channelCount] { m_ui->reverseR->isChecked(), m_ui->reverseG->isChecked(), m_ui->reverseB->isChecked(), m_ui->reverseA->isChecked() };
  510. //and which are fixed?
  511. bool fixed[c_channelCount] { m_ui->fixR->isChecked(), m_ui->fixG->isChecked(), m_ui->fixB->isChecked(), m_ui->fixA->isChecked() };
  512. //map scalar values to RGB
  513. if (m_ui->toggleRGB->isChecked())
  514. {
  515. int col[c_channelCount];
  516. for (unsigned p = 0; p < m_cloud->size(); p++)
  517. {
  518. //get col
  519. for (unsigned i = 0; i < c_channelCount; i++)
  520. {
  521. if (fixed[i]) //fixed value
  522. {
  523. col[i] = static_cast<int>(m_boxes_min[i]->value());
  524. }
  525. else //map from scalar
  526. {
  527. col[i] = static_cast<int>(255.0 * (m_scalars[i]->getValue(p) - m_minSat[i]) / (m_maxSat[i] - m_minSat[i]));
  528. }
  529. //trim to range 0 - 255
  530. col[i] = std::max(col[i], 0);
  531. col[i] = std::min(col[i], 255);
  532. //flip?
  533. if (reversed[i] && !fixed[i])
  534. {
  535. col[i] = 255 - col[i];
  536. }
  537. }
  538. m_cloud->setPointColor(p, ccColor::FromQColora(QColor(col[0], col[1], col[2], col[3])));
  539. }
  540. }
  541. else //map scalar values to HSV (and then to RGB)
  542. {
  543. float col[c_channelCount];
  544. for (unsigned p = 0; p < m_cloud->size(); p++)
  545. {
  546. //get col
  547. for (unsigned i = 0; i < c_channelCount; i++)
  548. {
  549. if (fixed[i]) //fixed value
  550. {
  551. col[i] = m_boxes_min[i]->value() / m_boxes_min[i]->maximum(); //n.b. most 'fixed' boxes between 0 - 255, but hue between 0 and 360.
  552. }
  553. else //map from scalar
  554. {
  555. col[i] = (m_scalars[i]->getValue(p) - m_minSat[i]) / (m_maxSat[i] - m_minSat[i]);
  556. }
  557. //trim to range 0 - 1
  558. col[i] = std::max(col[i], 0.0f);
  559. col[i] = std::min(col[i], 1.0f);
  560. //flip?
  561. if (reversed[i] && !fixed[i])
  562. {
  563. col[i] = 1.0f - col[i];
  564. }
  565. }
  566. //calculate and set colour
  567. ccColor::Rgb rgb = ccColor::Convert::hsv2rgb(col[0] * 360.0f, col[1], col[2]);
  568. m_cloud->setPointColor(p, ccColor::Rgba(rgb, static_cast<int>(col[3] * ccColor::MAX)));
  569. }
  570. }
  571. m_cloud->colorsHaveChanged();
  572. m_cloud->showSF(false);
  573. m_cloud->showColors(true);
  574. m_cloud->redrawDisplay();
  575. }
  576. }
  577. void ccColorFromScalarDlg::disableAllButCancel()
  578. {
  579. for (unsigned n = 0; n < c_channelCount; n++)
  580. {
  581. m_histograms[n]->setEnabled(false);
  582. m_combos[n]->setEnabled(false);
  583. m_boxes_min[n]->setEnabled(false);
  584. m_boxes_max[n]->setEnabled(false);
  585. m_labels_min[n]->setEnabled(false);
  586. m_labels_max[n]->setEnabled(false);
  587. m_reverse[n]->setEnabled(false);
  588. }
  589. m_ui->toggleHSV->setEnabled(false);
  590. m_ui->toggleRGB->setEnabled(false);
  591. m_ui->fixR->setEnabled(false);
  592. m_ui->fixG->setEnabled(false);
  593. m_ui->fixB->setEnabled(false);
  594. m_ui->fixA->setEnabled(false);
  595. m_ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
  596. }