File indexing completed on 2024-04-14 14:10:36

0001 /*
0002     SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "fitshistogrameditor.h"
0008 
0009 #include "fits_debug.h"
0010 
0011 #include "Options.h"
0012 #include "fitsdata.h"
0013 #include "fitstab.h"
0014 #include "fitsview.h"
0015 #include "fitsviewer.h"
0016 
0017 #include <KMessageBox>
0018 
0019 #include <QtConcurrent>
0020 #include <type_traits>
0021 
0022 histogramUI::histogramUI(QDialog * parent) : QDialog(parent)
0023 {
0024     setupUi(parent);
0025     setModal(false);
0026 }
0027 
0028 FITSHistogramEditor::FITSHistogramEditor(QWidget * parent) : QDialog(parent)
0029 {
0030     ui = new histogramUI(this);
0031 
0032     minBoxes << ui->minREdit << ui->minGEdit << ui->minBEdit;
0033     maxBoxes << ui->maxREdit << ui->maxGEdit << ui->maxBEdit;
0034     sliders << ui->redSlider << ui->greenSlider << ui->blueSlider;
0035 
0036     ui->histogramPlot->setProperty("linear", !Options::nonLinearHistogram());
0037 
0038     connect(ui->applyB, &QPushButton::clicked, this, &FITSHistogramEditor::applyScale);
0039     //    connect(ui->hideSaturated, &QCheckBox::stateChanged, [this]()
0040     //    {
0041     //        m_ImageData->resetHistogram();
0042     //        m_ImageData->constructHistogram();
0043     //        ui->histogramPlot->syncGUI();
0044     //    });
0045 
0046     rgbWidgets.resize(3);
0047     rgbWidgets[RED_CHANNEL] << ui->RLabel << ui->minREdit << ui->redSlider
0048                             << ui->maxREdit;
0049     rgbWidgets[GREEN_CHANNEL] << ui->GLabel << ui->minGEdit << ui->greenSlider
0050                               << ui->maxGEdit;
0051     rgbWidgets[BLUE_CHANNEL] << ui->BLabel << ui->minBEdit << ui->blueSlider
0052                              << ui->maxBEdit;
0053 
0054     for (int i = 0; i < 3; i++)
0055     {
0056         // Box --> Slider
0057         QVector<QWidget *> w = rgbWidgets[i];
0058         connect(qobject_cast<QDoubleSpinBox *>(w[1]), &QDoubleSpinBox::editingFinished, [this, i, w]()
0059         {
0060             double value = qobject_cast<QDoubleSpinBox *>(w[1])->value();
0061             w[2]->blockSignals(true);
0062             qobject_cast<ctkRangeSlider *>(w[2])->setMinimumPosition((value - m_ImageData->getMin(i))*sliderScale[i]);
0063             w[2]->blockSignals(false);
0064         });
0065         connect(qobject_cast<QDoubleSpinBox *>(w[3]), &QDoubleSpinBox::editingFinished, [this, i, w]()
0066         {
0067             double value = qobject_cast<QDoubleSpinBox *>(w[3])->value();
0068             w[2]->blockSignals(true);
0069             qobject_cast<ctkRangeSlider *>(w[2])->setMaximumPosition((value - m_ImageData->getMin(i) - sliderTick[i])*sliderScale[i]);
0070             w[2]->blockSignals(false);
0071         });
0072 
0073         // Slider --> Box
0074         connect(qobject_cast<ctkRangeSlider *>(w[2]), &ctkRangeSlider::minimumValueChanged, [this, i, w](int position)
0075         {
0076             qobject_cast<QDoubleSpinBox *>(w[1])->setValue(m_ImageData->getMin(i) + (position / sliderScale[i]));
0077         });
0078         connect(qobject_cast<ctkRangeSlider *>(w[2]), &ctkRangeSlider::maximumValueChanged, [this, i, w](int position)
0079         {
0080             qobject_cast<QDoubleSpinBox *>(w[3])->setValue(m_ImageData->getMin(i) + sliderTick[i] + (position / sliderScale[i]));
0081         });
0082     }
0083 }
0084 
0085 void FITSHistogramEditor::showEvent(QShowEvent * event)
0086 {
0087     Q_UNUSED(event)
0088     //    if (!Options::nonLinearHistogram() && !m_ImageData->isHistogramConstructed())
0089     //        m_ImageData->constructHistogram();
0090 
0091     syncGUI();
0092 
0093 }
0094 
0095 //void FITSHistogramEditor::createNonLinearHistogram()
0096 //{
0097 //    ui->histogramPlot->createNonLinearHistogram();
0098 //}
0099 
0100 void FITSHistogramEditor::resizePlot()
0101 {
0102     ui->histogramPlot->resizePlot();
0103 }
0104 
0105 void FITSHistogramEditor::syncGUI()
0106 {
0107     if (isGUISynced)
0108         return;
0109 
0110     sliderTick.clear();
0111     sliderScale.clear();
0112     for (int n = 0; n < m_ImageData->channels(); n++)
0113     {
0114         sliderTick  << fabs(m_ImageData->getMax(n) - m_ImageData->getMin(n)) / 99.0;
0115         sliderScale << 99.0 / (m_ImageData->getMax(n) - m_ImageData->getMin(n) - sliderTick[n]);
0116     }
0117 
0118     ui->histogramPlot->syncGUI();
0119 
0120     bool isColor = m_ImageData->channels() > 1;
0121     // R/K is always enabled
0122     for (auto w : rgbWidgets[RED_CHANNEL])
0123         w->setEnabled(true);
0124     // G Channel
0125     for (auto w : rgbWidgets[GREEN_CHANNEL])
0126         w->setEnabled(isColor);
0127     // B Channel
0128     for (auto w : rgbWidgets[BLUE_CHANNEL])
0129         w->setEnabled(isColor);
0130 
0131     ui->meanEdit->setText(QString::number(m_ImageData->getMean()));
0132     ui->medianEdit->setText(QString::number(m_ImageData->getMedian()));
0133 
0134     for (int n = 0; n < m_ImageData->channels(); n++)
0135     {
0136         double median = m_ImageData->getMedian(n);
0137 
0138         if (median > 100)
0139             numDecimals << 0;
0140         else if (median > 1)
0141             numDecimals << 2;
0142         else if (median > .01)
0143             numDecimals << 4;
0144         else if (median > .0001)
0145             numDecimals << 6;
0146         else
0147             numDecimals << 10;
0148 
0149         minBoxes[n]->setDecimals(numDecimals[n]);
0150         minBoxes[n]->setSingleStep(fabs(m_ImageData->getMax(n) - m_ImageData->getMin(n)) / 20.0);
0151         minBoxes[n]->setMinimum(m_ImageData->getMin(n));
0152         minBoxes[n]->setMaximum(m_ImageData->getMax(n) - sliderTick[n]);
0153         minBoxes[n]->setValue(m_ImageData->getMin(n) + (sliders[n]->minimumValue() / sliderScale[n]));
0154 
0155         maxBoxes[n]->setDecimals(numDecimals[n]);
0156         maxBoxes[n]->setSingleStep(fabs(m_ImageData->getMax(n) - m_ImageData->getMin(n)) / 20.0);
0157         maxBoxes[n]->setMinimum(m_ImageData->getMin(n) + sliderTick[n]);
0158         maxBoxes[n]->setMaximum(m_ImageData->getMax(n));
0159         maxBoxes[n]->setValue(m_ImageData->getMin(n) + sliderTick[n] + (sliders[n]->maximumValue() / sliderScale[n]));
0160     }
0161 
0162     ui->histogramPlot->syncGUI();
0163 
0164     isGUISynced = true;
0165 }
0166 
0167 
0168 
0169 void FITSHistogramEditor::applyScale()
0170 {
0171     QVector<double> min, max;
0172 
0173     min << minBoxes[0]->value() << minBoxes[1]->value() <<  minBoxes[2]->value();
0174     max << maxBoxes[0]->value() << maxBoxes[1]->value() << maxBoxes[2]->value();
0175 
0176     //    if (ui->logR->isChecked())
0177     //        type = FITS_LOG;
0178     //    else
0179     type = FITS_LINEAR;
0180     emit newHistogramCommand(new FITSHistogramCommand(m_ImageData, this, type, min, max));
0181 }
0182 
0183 void FITSHistogramEditor::applyFilter(FITSScale ftype)
0184 {
0185     QVector<double> min, max;
0186     min.append(ui->minREdit->value());
0187     type = ftype;
0188 
0189     emit newHistogramCommand(new FITSHistogramCommand(m_ImageData, this, type, min, max));
0190 }
0191 
0192 void FITSHistogramEditor::setImageData(const QSharedPointer<FITSData> &data)
0193 {
0194     m_ImageData = data;
0195     ui->histogramPlot->setImageData(data);
0196 
0197     connect(m_ImageData.data(), &FITSData::dataChanged, [this]
0198     {
0199         isGUISynced = false;
0200         syncGUI();
0201     });
0202 }