File indexing completed on 2024-03-24 15:17:02
0001 /* 0002 SPDX-FileCopyrightText: 2017 Robert Lancaster <rlancaste@gmail.com> 0003 0004 Based on the QT Surface Example https://doc.qt.io/qt-5.9/qtdatavisualization-surface-example.html 0005 and the QT Bars Example https://doc-snapshots.qt.io/qt5-5.9/qtdatavisualization-bars-example.html 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "starprofileviewer.h" 0011 #include <KLocalizedString> 0012 0013 using namespace QtDataVisualization; 0014 0015 StarProfileViewer::StarProfileViewer(QWidget *parent) : QDialog(parent) 0016 { 0017 0018 #ifdef Q_OS_OSX 0019 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0020 #endif 0021 0022 m_graph = new Q3DBars(); 0023 m_pixelValueAxis = m_graph->valueAxis(); 0024 m_xPixelAxis = m_graph->columnAxis(); 0025 m_yPixelAxis = m_graph->rowAxis(); 0026 0027 m_pixelValueAxis->setTitle(i18n("Pixel Values")); 0028 m_pixelValueAxis->setLabelAutoRotation(30.0f); 0029 m_pixelValueAxis->setTitleVisible(true); 0030 0031 m_xPixelAxis->setTitle(i18n("Horizontal")); 0032 m_xPixelAxis->setLabelAutoRotation(30.0f); 0033 m_xPixelAxis->setTitleVisible(true); 0034 m_yPixelAxis->setTitle(i18n("Vertical")); 0035 m_yPixelAxis->setLabelAutoRotation(30.0f); 0036 m_yPixelAxis->setTitleVisible(true); 0037 0038 m_3DPixelSeries = new QBar3DSeries; 0039 0040 m_3DPixelSeries->setMesh(QAbstract3DSeries::MeshBevelBar); 0041 m_graph->addSeries(m_3DPixelSeries); 0042 0043 m_graph->activeTheme()->setLabelBackgroundEnabled(false); 0044 0045 QWidget *container = QWidget::createWindowContainer(m_graph); 0046 0047 if (!m_graph->hasContext()) { 0048 QMessageBox msgBox; 0049 msgBox.setText(i18n("Couldn't initialize the OpenGL context.")); 0050 msgBox.exec(); 0051 return; 0052 } 0053 0054 QSize screenSize = m_graph->screen()->size(); 0055 container->setMinimumSize(QSize(300, 500)); 0056 container->setMaximumSize(screenSize); 0057 container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0058 container->setFocusPolicy(Qt::StrongFocus); 0059 0060 this->setWindowTitle(i18nc("@title:window", "View Star Profile")); 0061 0062 QVBoxLayout *mainLayout = new QVBoxLayout(this); 0063 QHBoxLayout *topLayout = new QHBoxLayout(); 0064 QHBoxLayout *controlsLayout = new QHBoxLayout(); 0065 QWidget* rightWidget = new QWidget(); 0066 rightWidget->setVisible(false); 0067 QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget); 0068 QGridLayout *sliderLayout = new QGridLayout(); 0069 0070 topLayout->addWidget(container, 1); 0071 topLayout->addWidget(rightWidget); 0072 mainLayout->addLayout(topLayout); 0073 mainLayout->addLayout(controlsLayout); 0074 controlsLayout->setAlignment(Qt::AlignLeft); 0075 0076 maxValue=new QLabel(this); 0077 maxValue->setToolTip(i18n("Maximum Value on the graph")); 0078 cutoffValue=new QLabel(this); 0079 cutoffValue->setToolTip(i18n("Cuttoff Maximum for eliminating hot pixels and bright stars.")); 0080 0081 QCheckBox *toggleEnableCutoff= new QCheckBox(this); 0082 toggleEnableCutoff->setToolTip(i18n("Enable or Disable the Max Value Cutoff")); 0083 toggleEnableCutoff->setText(i18n("Toggle Cutoff")); 0084 toggleEnableCutoff->setChecked(false); 0085 0086 blackPointSlider=new QSlider( Qt::Vertical, this); 0087 blackPointSlider->setToolTip(i18n("Sets the Minimum Value on the graph")); 0088 sliderLayout->addWidget(blackPointSlider,0,0); 0089 sliderLayout->addWidget(new QLabel(i18n("Min")),1,0); 0090 0091 whitePointSlider=new QSlider( Qt::Vertical, this); 0092 whitePointSlider->setToolTip(i18n("Sets the Maximum Value on the graph")); 0093 sliderLayout->addWidget(whitePointSlider,0,1); 0094 sliderLayout->addWidget(new QLabel(i18n("Max")),1,1); 0095 0096 cutoffSlider=new QSlider( Qt::Vertical, this); 0097 cutoffSlider->setToolTip(i18n("Sets the Cuttoff Maximum for eliminating hot pixels and bright stars.")); 0098 sliderLayout->addWidget(cutoffSlider,0,2); 0099 sliderLayout->addWidget(new QLabel(i18n("Cut")),1,2); 0100 cutoffSlider->setEnabled(false); 0101 0102 minValue = new QLabel(this); 0103 minValue->setToolTip(i18n("Minimum Value on the graph")); 0104 0105 autoScale = new QCheckBox(this); 0106 autoScale->setText(i18n("AutoScale")); 0107 autoScale->setToolTip(i18n("Automatically scales the sliders for the subFrame.\nUncheck to leave them unchanged when you pan around.")); 0108 autoScale->setChecked(true); 0109 0110 showScaling = new QPushButton(this); 0111 showScaling->setIcon(QIcon::fromTheme("transform-move-vertical")); 0112 showScaling->setCheckable(true); 0113 showScaling->setMaximumSize(22, 22); 0114 showScaling->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0115 showScaling->setToolTip(i18n("Hides and shows the scaling side panel")); 0116 showScaling->setChecked(false); 0117 0118 rightLayout->addWidget(toggleEnableCutoff); 0119 rightLayout->addWidget(cutoffValue); 0120 rightLayout->addWidget(maxValue); 0121 rightLayout->addLayout(sliderLayout); 0122 rightLayout->addWidget(minValue); 0123 rightLayout->addWidget(autoScale); 0124 0125 selectionType = new QComboBox(this); 0126 selectionType->setToolTip(i18n("Changes the type of selection")); 0127 selectionType->addItem(i18n("Item")); 0128 selectionType->addItem(i18n("Horizontal")); 0129 selectionType->addItem(i18n("Vertical")); 0130 selectionType->setCurrentIndex(0); 0131 0132 sliceB = new QPushButton(this); 0133 sliceB->setIcon(QIcon::fromTheme("view-object-histogram-linear")); 0134 sliceB->setCheckable(true); 0135 sliceB->setMaximumSize(22, 22); 0136 sliceB->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0137 sliceB->setToolTip(i18n("Toggles the slice view when horizontal or vertical items are selected")); 0138 sliceB->setCheckable(true); 0139 sliceB->setChecked(false); 0140 sliceB->setEnabled(false); 0141 sliceB->setDefault(false); 0142 0143 showCoordinates = new QPushButton(this); 0144 showCoordinates->setIcon(QIcon::fromTheme("coordinate")); 0145 showCoordinates->setCheckable(true); 0146 showCoordinates->setMaximumSize(22, 22); 0147 showCoordinates->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0148 showCoordinates->setToolTip(i18n("Shows the x, y coordinates of star centers in the frame")); 0149 showCoordinates->setChecked(false); 0150 0151 HFRReport = new QPushButton(this); 0152 HFRReport->setToolTip(i18n("Shows the HFR of stars in the frame")); 0153 HFRReport->setIcon(QIcon::fromTheme("tool-measure")); 0154 HFRReport->setCheckable(true); 0155 HFRReport->setMaximumSize(22, 22); 0156 HFRReport->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0157 HFRReport->setChecked(true); 0158 0159 reportBox = new QLabel(this); 0160 0161 showPeakValues = new QPushButton(this); 0162 showPeakValues->setIcon(QIcon::fromTheme("kruler-east")); 0163 showPeakValues->setCheckable(true); 0164 showPeakValues->setMaximumSize(22, 22); 0165 showPeakValues->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0166 showPeakValues->setToolTip(i18n("Shows the peak values of star centers in the frame")); 0167 showPeakValues->setChecked(true); 0168 0169 sampleSize = new QComboBox(this); 0170 sampleSize->setToolTip(i18n("Changes the sample size shown in the graph")); 0171 sampleSize->addItem(QString::number(16)); 0172 sampleSize->addItem(QString::number(32)); 0173 sampleSize->addItem(QString::number(64)); 0174 sampleSize->addItem(QString::number(128)); 0175 sampleSize->addItem(QString::number(256)); 0176 sampleSize->addItem(QString::number(512)); 0177 sampleSize->setCurrentIndex(3); 0178 sampleSize->setVisible(false); 0179 0180 zoomView = new QComboBox(this); 0181 zoomView->setToolTip(i18n("Zooms the view to preset locations.")); 0182 zoomView->addItem(i18n("ZoomTo")); 0183 zoomView->addItem(i18n("Front")); 0184 zoomView->addItem(i18n("Front High")); 0185 zoomView->addItem(i18n("Overhead")); 0186 zoomView->addItem(i18n("Iso. L")); 0187 zoomView->addItem(i18n("Iso. R")); 0188 zoomView->addItem(i18n("Selected")); 0189 zoomView->setCurrentIndex(0); 0190 0191 QPushButton *selectorsVisible = new QPushButton(this); 0192 selectorsVisible->setIcon(QIcon::fromTheme("adjustlevels")); 0193 selectorsVisible->setCheckable(true); 0194 selectorsVisible->setMaximumSize(22, 22); 0195 selectorsVisible->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0196 selectorsVisible->setToolTip(i18n("Hides and shows the Vertical and Horizontal Selection Sliders")); 0197 selectorsVisible->setChecked(false); 0198 0199 controlsLayout->addWidget(sampleSize); 0200 controlsLayout->addWidget(selectionType); 0201 controlsLayout->addWidget(selectorsVisible); 0202 controlsLayout->addWidget(sliceB); 0203 controlsLayout->addWidget(showScaling); 0204 //bottomLayout->addWidget(barSpacing); 0205 controlsLayout->addWidget(zoomView); 0206 //bottomLayout->addWidget(color); 0207 controlsLayout->addWidget(showCoordinates); 0208 controlsLayout->addWidget(HFRReport); 0209 controlsLayout->addWidget(showPeakValues); 0210 controlsLayout->addWidget(reportBox); 0211 0212 QWidget *bottomSliderWidget= new QWidget(this); 0213 QGridLayout *bottomSliders = new QGridLayout(bottomSliderWidget); 0214 bottomSliderWidget->setLayout(bottomSliders); 0215 mainLayout->addWidget(bottomSliderWidget); 0216 bottomSliderWidget->setVisible(false); 0217 0218 verticalSelector = new QSlider(Qt::Horizontal, this); 0219 verticalSelector->setToolTip(i18n("Selects the Vertical Value")); 0220 horizontalSelector = new QSlider(Qt::Horizontal, this); 0221 horizontalSelector->setToolTip(i18n("Selects the Horizontal Value")); 0222 0223 bottomSliders->addWidget(new QLabel(i18n("Vertical: ")), 0, 0); 0224 bottomSliders->addWidget(verticalSelector, 0, 1); 0225 bottomSliders->addWidget(new QLabel(i18n("Horizontal: ")), 1, 0); 0226 bottomSliders->addWidget(horizontalSelector, 1, 1); 0227 0228 QWidget *bottomControlsWidget= new QWidget(this); 0229 QHBoxLayout *bottomControlLayout = new QHBoxLayout(bottomControlsWidget); 0230 mainLayout->addWidget(bottomControlsWidget);\ 0231 bottomControlsWidget->setVisible(false); 0232 0233 exploreMode = new QPushButton(this); 0234 exploreMode->setIcon(QIcon::fromTheme("visibility")); 0235 exploreMode->setCheckable(true); 0236 exploreMode->setMaximumSize(22, 22); 0237 exploreMode->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0238 exploreMode->setToolTip(i18n("Zooms automatically as the sliders change")); 0239 exploreMode->setChecked(true); 0240 0241 QDial *barSpacing=new QDial(this); 0242 barSpacing->setMinimum(0); 0243 barSpacing->setMaximum(100); 0244 barSpacing->setValue(50); 0245 barSpacing->setMaximumSize(32, 32); 0246 barSpacing->setWrapping(false); 0247 m_graph->setBarSpacing(QSizeF(0.5,0.5)); 0248 0249 QComboBox *color = new QComboBox(this); 0250 color->setToolTip(i18n("Changes the color scheme")); 0251 0252 QLinearGradient grGtoR(50, 1, 0, 0); 0253 grGtoR.setColorAt(1.0, Qt::darkGreen); 0254 grGtoR.setColorAt(0.5, Qt::yellow); 0255 grGtoR.setColorAt(0.2, Qt::red); 0256 grGtoR.setColorAt(0.0, Qt::darkRed); 0257 QPixmap pm(50, 10); 0258 QPainter pmp(&pm); 0259 pmp.setPen(Qt::NoPen); 0260 pmp.setBrush(QBrush(grGtoR)); 0261 pmp.drawRect(0, 0, 50, 10); 0262 color->addItem(""); 0263 color->setItemIcon(0,QIcon(pm)); 0264 0265 QLinearGradient grBtoY(50, 1, 0, 0); 0266 grBtoY.setColorAt(1.0, Qt::black); 0267 grBtoY.setColorAt(0.67, Qt::blue); 0268 grBtoY.setColorAt(0.33, Qt::red); 0269 grBtoY.setColorAt(0.0, Qt::yellow); 0270 pmp.setBrush(QBrush(grBtoY)); 0271 pmp.drawRect(0, 0, 50, 10); 0272 color->addItem(""); 0273 color->setItemIcon(1,QIcon(pm)); 0274 0275 color->setIconSize(QSize(50, 10)); 0276 color->setCurrentIndex(0); 0277 color->setMaximumWidth(80); 0278 0279 pixelReport = new QLabel("", bottomControlsWidget); 0280 0281 bottomControlLayout->addWidget(exploreMode); 0282 bottomControlLayout->addWidget(barSpacing); 0283 bottomControlLayout->addWidget(color); 0284 bottomControlLayout->addWidget(pixelReport); 0285 0286 QObject::connect(selectionType, SIGNAL(currentIndexChanged(int)), 0287 this, SLOT(changeSelectionType(int))); 0288 QObject::connect(zoomView, SIGNAL(currentIndexChanged(int)), 0289 this, SLOT(zoomViewTo(int))); 0290 QObject::connect(sliceB, &QPushButton::pressed, 0291 this, &StarProfileViewer::toggleSlice); 0292 QObject::connect(showCoordinates, &QCheckBox::toggled, 0293 this, &StarProfileViewer::updateHFRandPeakSelection); 0294 QObject::connect(HFRReport, &QCheckBox::toggled, 0295 this, &StarProfileViewer::updateHFRandPeakSelection); 0296 QObject::connect(showPeakValues, &QCheckBox::toggled, 0297 this, &StarProfileViewer::updateHFRandPeakSelection); 0298 QObject::connect(blackPointSlider, &QSlider::valueChanged, 0299 this, &StarProfileViewer::updateVerticalAxis); 0300 QObject::connect(whitePointSlider, &QSlider::valueChanged, 0301 this, &StarProfileViewer::updateVerticalAxis); 0302 QObject::connect(cutoffSlider, &QSlider::valueChanged, 0303 this, &StarProfileViewer::updateDisplayData); 0304 QObject::connect(autoScale, &QCheckBox::toggled, 0305 this, &StarProfileViewer::updateScale); 0306 QObject::connect(showScaling, &QCheckBox::toggled, 0307 rightWidget, &QWidget::setVisible); 0308 QObject::connect(sampleSize, SIGNAL(currentIndexChanged(QString)), 0309 this, SLOT(updateSampleSize(QString))); 0310 QObject::connect(color, SIGNAL(currentIndexChanged(int)), 0311 this, SLOT(updateColor(int))); 0312 QObject::connect(verticalSelector, &QSlider::valueChanged, 0313 this, &StarProfileViewer::changeSelection); 0314 QObject::connect(horizontalSelector, &QSlider::valueChanged, 0315 this, &StarProfileViewer::changeSelection); 0316 QObject::connect(selectorsVisible, &QCheckBox::toggled, 0317 bottomSliderWidget, &QWidget::setVisible); 0318 QObject::connect(selectorsVisible, &QCheckBox::toggled, 0319 bottomControlsWidget, &QWidget::setVisible); 0320 QObject::connect(toggleEnableCutoff, &QCheckBox::toggled, 0321 this, &StarProfileViewer::toggleCutoffEnabled); 0322 QObject::connect(m_3DPixelSeries, &QBar3DSeries::selectedBarChanged, 0323 this, &StarProfileViewer::updateSelectorBars); 0324 QObject::connect(barSpacing, &QSlider::valueChanged, 0325 this, &StarProfileViewer::updateBarSpacing); 0326 0327 m_graph->activeTheme()->setType(Q3DTheme::Theme(3)); //Stone Moss 0328 0329 setGreenToRedGradient(); 0330 0331 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront); 0332 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); 0333 m_graph->scene()->activeCamera()->setZoomLevel(110); 0334 0335 //Note: This is to prevent a button from being called the default button 0336 //and then executing when the user hits the enter key such as when on a Text Box 0337 #ifdef Q_OS_OSX 0338 QList<QPushButton *> qButtons = findChildren<QPushButton *>(); 0339 for (auto &button : qButtons) 0340 button->setAutoDefault(false); 0341 #endif 0342 0343 show(); 0344 } 0345 0346 StarProfileViewer::~StarProfileViewer() 0347 { 0348 delete m_graph; 0349 } 0350 0351 void StarProfileViewer::loadData(QSharedPointer<FITSData> data, QRect sub, QList<Edge *> centers) 0352 { 0353 if(data) 0354 { 0355 imageData = data; 0356 subFrame=sub; 0357 starCenters=centers; 0358 0359 switch (data->getStatistics().dataType) 0360 { 0361 case TBYTE: 0362 loadDataPrivate<uint8_t>(); 0363 break; 0364 0365 case TSHORT: 0366 loadDataPrivate<int16_t>(); 0367 break; 0368 0369 case TUSHORT: 0370 loadDataPrivate<uint16_t>(); 0371 break; 0372 0373 case TLONG: 0374 loadDataPrivate<int32_t>(); 0375 break; 0376 0377 case TULONG: 0378 loadDataPrivate<uint32_t>(); 0379 break; 0380 0381 case TFLOAT: 0382 loadDataPrivate<float>(); 0383 break; 0384 0385 case TLONGLONG: 0386 loadDataPrivate<int64_t>(); 0387 break; 0388 0389 case TDOUBLE: 0390 loadDataPrivate<double>(); 0391 break; 0392 } 0393 0394 updateScale(); 0395 0396 // Add data to the data proxy (the data proxy assumes ownership of it) 0397 // We will retain a copy of the data set so that we can update the display 0398 updateDisplayData(); 0399 0400 updateHFRandPeakSelection(); 0401 0402 horizontalSelector->setRange(0, subFrame.width()-1); 0403 verticalSelector->setRange(0, subFrame.width()-1); //Width and height are the same 0404 } 0405 } 0406 0407 template <typename T> 0408 void StarProfileViewer::loadDataPrivate() 0409 { 0410 // Create data arrays 0411 dataSet = new QBarDataArray; 0412 QBarDataRow *dataRow; 0413 dataSet->reserve(subFrame.height()); 0414 QStringList rowLabels; 0415 QStringList columnLabels; 0416 0417 auto *buffer = reinterpret_cast<T const *>(imageData->getImageBuffer()); 0418 int width = imageData->width(); 0419 0420 for (int j = subFrame.y(); j < subFrame.y() + subFrame.height(); j++) 0421 { 0422 if( j % 10 == 0 ) 0423 rowLabels << QString::number(j); 0424 else 0425 rowLabels << ""; 0426 dataRow = new QBarDataRow(subFrame.width()); 0427 int x = 0; 0428 for (int i = subFrame.x(); i < subFrame.x() + subFrame.width(); i++) 0429 { 0430 if( i % 10 == 0 ) 0431 columnLabels << QString::number(i); 0432 else 0433 columnLabels << ""; 0434 if( i > 0 && i < imageData->width() && j > 0 && j < imageData->height()) 0435 (*dataRow)[x].setValue(*(buffer + i + j * width)); 0436 x++; 0437 } 0438 dataSet->insert(0, dataRow); //Note the row axis is displayed in the opposite direction of the y axis in the image. 0439 } 0440 0441 std::reverse(rowLabels.begin(), rowLabels.end()); 0442 0443 m_3DPixelSeries->dataProxy()->setRowLabels(rowLabels); 0444 m_3DPixelSeries->dataProxy()->setColumnLabels(columnLabels); 0445 } 0446 0447 void StarProfileViewer::toggleCutoffEnabled(bool enable) 0448 { 0449 cutoffSlider->setEnabled(enable); 0450 cutOffEnabled = enable; 0451 updateDisplayData(); 0452 } 0453 0454 void StarProfileViewer::updateScale() 0455 { 0456 0457 //We need to disconnect these so that changing their ranges doesn't affect things 0458 QObject::disconnect(blackPointSlider, &QSlider::valueChanged, 0459 this, &StarProfileViewer::updateVerticalAxis); 0460 QObject::disconnect(whitePointSlider, &QSlider::valueChanged, 0461 this, &StarProfileViewer::updateVerticalAxis); 0462 QObject::disconnect(cutoffSlider, &QSlider::valueChanged, 0463 this, &StarProfileViewer::updateDisplayData); 0464 0465 float subFrameMin, subFrameMax; 0466 double dataMin, dataMax; 0467 float min, max; 0468 getSubFrameMinMax(&subFrameMin, &subFrameMax, &dataMin, &dataMax); 0469 0470 int sliderDataMin = convertToSliderValue(dataMin) - 1; //Expands the slider range a little beyond the max and min values 0471 int sliderDataMax = convertToSliderValue(dataMax) + 1; 0472 0473 if(autoScale->isChecked()) 0474 { 0475 min = subFrameMin; 0476 max = subFrameMax; 0477 int sliderMin = convertToSliderValue(min) - 1; //Expands the slider range a little beyond the max and min values 0478 int sliderMax = convertToSliderValue(max) + 1; 0479 blackPointSlider->setRange(sliderMin, sliderMax); 0480 blackPointSlider->setTickInterval((sliderMax - sliderMin) / 100); 0481 whitePointSlider->setRange(sliderMin, sliderMax); 0482 whitePointSlider->setTickInterval((sliderMax - sliderMin) / 100); 0483 cutoffSlider->setRange(sliderMin, sliderDataMax); 0484 cutoffSlider->setTickInterval((sliderDataMax - sliderMin) / 100); 0485 blackPointSlider->setValue(sliderMin); 0486 whitePointSlider->setValue(sliderMax); 0487 cutoffSlider->setValue(sliderDataMax); 0488 } 0489 else 0490 { 0491 min = convertFromSliderValue(blackPointSlider->value()); 0492 max = convertFromSliderValue(whitePointSlider->value()); 0493 blackPointSlider->setRange(sliderDataMin, sliderDataMax); 0494 blackPointSlider->setTickInterval((sliderDataMax - sliderDataMin) / 100); 0495 whitePointSlider->setRange(sliderDataMin, sliderDataMax); 0496 whitePointSlider->setTickInterval((sliderDataMax - sliderDataMin) / 100); 0497 cutoffSlider->setRange(sliderDataMin, sliderDataMax); 0498 cutoffSlider->setTickInterval((sliderDataMax - sliderDataMin) / 100); 0499 0500 } 0501 m_pixelValueAxis->setRange(min, max); 0502 0503 if(cutOffEnabled) 0504 cutoffValue->setText(i18n("Cut: %1", roundf(convertFromSliderValue(cutoffSlider->value()) * 100) / 100)); 0505 else 0506 cutoffValue->setText("Cut Disabled"); 0507 0508 if(max < 10 ) 0509 { 0510 m_pixelValueAxis->setLabelFormat(QString(QStringLiteral("%.3f "))); 0511 m_3DPixelSeries->setItemLabelFormat(QString(QStringLiteral("%.3f "))); 0512 maxValue->setText(i18n("Max: %1", roundf(max * 100) / 100)); 0513 minValue->setText(i18n("Min: %1", roundf(min * 100) / 100)); 0514 } 0515 else 0516 { 0517 m_pixelValueAxis->setLabelFormat(QString(QStringLiteral("%.0f "))); 0518 m_3DPixelSeries->setItemLabelFormat(QString(QStringLiteral("%.0f "))); 0519 maxValue->setText(i18n("Max: %1", max)); 0520 minValue->setText(i18n("Min: %1", min)); 0521 } 0522 0523 QObject::connect(blackPointSlider, &QSlider::valueChanged, 0524 this, &StarProfileViewer::updateVerticalAxis); 0525 QObject::connect(whitePointSlider, &QSlider::valueChanged, 0526 this, &StarProfileViewer::updateVerticalAxis); 0527 QObject::connect(cutoffSlider, &QSlider::valueChanged, 0528 this, &StarProfileViewer::updateDisplayData); 0529 } 0530 0531 void StarProfileViewer::updateBarSpacing(int value) 0532 { 0533 float spacing = (float)value/100.0; 0534 m_graph->setBarSpacing(QSizeF(spacing, spacing)); 0535 } 0536 0537 void StarProfileViewer::zoomViewTo(int where) 0538 { 0539 if(where > 6) //One of the star centers 0540 { 0541 int star = where - 7; 0542 int x = starCenters[star]->x - subFrame.x(); 0543 int y = subFrame.height() - (starCenters[star]->y - subFrame.y()); 0544 m_graph->primarySeries()->setSelectedBar(QPoint( y , x )); //Note row, column y, x 0545 where = 6; //This is so it will zoom to the target. 0546 } 0547 0548 switch (where) { 0549 case 0: //Zoom To 0550 break; 0551 0552 case 1: //Front 0553 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront); 0554 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); 0555 m_graph->scene()->activeCamera()->setZoomLevel(110); 0556 zoomView->setCurrentIndex(0); 0557 break; 0558 0559 case 2: //Front High 0560 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFrontHigh); 0561 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); 0562 m_graph->scene()->activeCamera()->setZoomLevel(110); 0563 zoomView->setCurrentIndex(0); 0564 break; 0565 0566 case 3: //Overhead 0567 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetDirectlyAbove); 0568 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); 0569 m_graph->scene()->activeCamera()->setZoomLevel(110); 0570 zoomView->setCurrentIndex(0); 0571 break; 0572 0573 case 4: //Isometric L 0574 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeftHigh); 0575 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); 0576 m_graph->scene()->activeCamera()->setZoomLevel(110); 0577 zoomView->setCurrentIndex(0); 0578 break; 0579 0580 case 5: //Isometric R 0581 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricRightHigh); 0582 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); 0583 m_graph->scene()->activeCamera()->setZoomLevel(110); 0584 zoomView->setCurrentIndex(0); 0585 break; 0586 0587 case 6: //Selected Item 0588 { 0589 QPoint selectedBar = m_graph->selectedSeries() 0590 ? m_graph->selectedSeries()->selectedBar() 0591 : QBar3DSeries::invalidSelectionPosition(); 0592 if (selectedBar != QBar3DSeries::invalidSelectionPosition()) 0593 { 0594 QVector3D target; 0595 float xMin = m_graph->columnAxis()->min(); 0596 float xRange = m_graph->columnAxis()->max() - xMin; 0597 float zMin = m_graph->rowAxis()->min(); 0598 float zRange = m_graph->rowAxis()->max() - zMin; 0599 target.setX((selectedBar.y() - xMin) / xRange * 2.0f - 1.0f); 0600 target.setZ((selectedBar.x() - zMin) / zRange * 2.0f - 1.0f); 0601 0602 qreal endAngleX = qAtan(qreal(target.z() / target.x())) / M_PI * -180.0 + 90.0; 0603 if (target.x() > 0.0f) 0604 endAngleX -= 180.0f; 0605 float barValue = m_graph->selectedSeries()->dataProxy()->itemAt(selectedBar.x(), 0606 selectedBar.y())->value(); 0607 float endAngleY = 60.0f; 0608 float zoom = 150 * 1/qSqrt(barValue / convertFromSliderValue(whitePointSlider->value())); 0609 m_graph->scene()->activeCamera()->setCameraPosition(endAngleX, endAngleY, zoom); 0610 m_graph->scene()->activeCamera()->setTarget(target); 0611 0612 0613 } 0614 zoomView->setCurrentIndex(0); 0615 break; 0616 } 0617 0618 0619 default: 0620 zoomView->setCurrentIndex(0); 0621 break; 0622 } 0623 } 0624 0625 void StarProfileViewer::changeSelectionType(int type) 0626 { 0627 switch (type) { 0628 case 0: 0629 m_graph->setSelectionMode(QAbstract3DGraph::SelectionItem); 0630 m_graph->scene()->setSlicingActive(false); 0631 sliceB->setEnabled(false); 0632 break; 0633 0634 case 1: 0635 m_graph->setSelectionMode(QAbstract3DGraph::SelectionItemAndRow); 0636 sliceB->setEnabled(true); 0637 break; 0638 0639 case 2: 0640 m_graph->setSelectionMode(QAbstract3DGraph::SelectionItemAndColumn); 0641 sliceB->setEnabled(true); 0642 break; 0643 0644 default: 0645 break; 0646 } 0647 } 0648 0649 void StarProfileViewer::changeSelection() 0650 { 0651 int x = horizontalSelector->value(); 0652 int y = verticalSelector->value(); 0653 m_graph->primarySeries()->setSelectedBar(QPoint( y , x )); //Note row, column y, x 0654 if(exploreMode->isChecked()) 0655 zoomViewTo(6); //Zoom to SelectedItem 0656 updatePixelReport(); 0657 } 0658 0659 void StarProfileViewer::updatePixelReport() 0660 { 0661 int x = horizontalSelector->value(); 0662 int y = verticalSelector->value(); 0663 //They need to be shifted to the location of the subframe 0664 x += subFrame.x(); 0665 y = (subFrame.height() - 1 - y) + subFrame.y(); //Note: Y is in reverse order on the graph. 0666 float barValue = getImageDataValue(x, y); 0667 pixelReport->setText(i18n("Selected Pixel: (%1, %2): %3", x + 1, y + 1, roundf(barValue * 100) / 100)); //Have to add 1 because humans start counting at 1 0668 0669 } 0670 0671 0672 void StarProfileViewer::updateSelectorBars(QPoint position) 0673 { 0674 //Note that we need to disconnect and then reconnect to avoid triggering changeSelection 0675 QObject::disconnect(verticalSelector, &QSlider::valueChanged, 0676 this, &StarProfileViewer::changeSelection); 0677 QObject::disconnect(horizontalSelector, &QSlider::valueChanged, 0678 this, &StarProfileViewer::changeSelection); 0679 0680 //Note row, column y, x 0681 verticalSelector->setValue(position.x()); 0682 horizontalSelector->setValue(position.y()); 0683 updatePixelReport(); 0684 0685 QObject::connect(verticalSelector, &QSlider::valueChanged, 0686 this, &StarProfileViewer::changeSelection); 0687 QObject::connect(horizontalSelector, &QSlider::valueChanged, 0688 this, &StarProfileViewer::changeSelection); 0689 } 0690 0691 void StarProfileViewer::updateSampleSize(const QString &text) 0692 { 0693 emit sampleSizeUpdated(text.toInt()); 0694 } 0695 0696 void StarProfileViewer::enableTrackingBox(bool enable) 0697 { 0698 sampleSize->setVisible(enable); 0699 } 0700 0701 void StarProfileViewer::updateDisplayData() 0702 { 0703 if(cutOffEnabled) 0704 cutoffValue->setText(i18n("Cut: %1", roundf(convertFromSliderValue(cutoffSlider->value()) * 100) / 100)); 0705 else 0706 cutoffValue->setText(i18n("Cut Disabled")); 0707 if(dataSet != nullptr) 0708 { 0709 QBarDataArray *displayDataSet = new QBarDataArray; 0710 displayDataSet->reserve(dataSet->size()); 0711 0712 for (int row = 0; row < dataSet->size(); row++) 0713 { 0714 QBarDataRow *dataRow = dataSet->at(row); 0715 QBarDataRow *newDataRow; 0716 newDataRow = new QBarDataRow(dataRow->size()); 0717 for (int column = 0; column < dataRow->size(); column++) 0718 { 0719 if(cutOffEnabled && dataRow->value(column).value() > convertFromSliderValue(cutoffSlider->value())) 0720 (*newDataRow)[column].setValue(0.0f); 0721 else 0722 (*newDataRow)[column].setValue(dataRow->value(column).value()); 0723 } 0724 displayDataSet->append(newDataRow); 0725 0726 } 0727 m_3DPixelSeries->dataProxy()->resetArray(displayDataSet); //, m_3DPixelSeries->dataProxy()->rowLabels(), m_3DPixelSeries->dataProxy()->columnLabels() 0728 } 0729 } 0730 0731 void StarProfileViewer::getSubFrameMinMax(float *subFrameMin, float *subFrameMax, double *dataMin, double *dataMax) 0732 { 0733 imageData->getMinMax(dataMin,dataMax); 0734 0735 //Backwards so that we can find the min and max in subFrame 0736 *subFrameMin = *dataMax; 0737 *subFrameMax = *dataMin; 0738 0739 switch (imageData->getStatistics().dataType) 0740 { 0741 case TBYTE: 0742 getSubFrameMinMax<uint8_t>(subFrameMin, subFrameMax); 0743 break; 0744 0745 case TSHORT: 0746 getSubFrameMinMax<int16_t>(subFrameMin, subFrameMax); 0747 break; 0748 0749 case TUSHORT: 0750 getSubFrameMinMax<uint16_t>(subFrameMin, subFrameMax); 0751 break; 0752 0753 case TLONG: 0754 getSubFrameMinMax<int32_t>(subFrameMin, subFrameMax); 0755 break; 0756 0757 case TULONG: 0758 getSubFrameMinMax<uint32_t>(subFrameMin, subFrameMax); 0759 break; 0760 0761 case TFLOAT: 0762 getSubFrameMinMax<float>(subFrameMin, subFrameMax); 0763 break; 0764 0765 case TLONGLONG: 0766 getSubFrameMinMax<int64_t>(subFrameMin, subFrameMax); 0767 break; 0768 0769 case TDOUBLE: 0770 getSubFrameMinMax<double>(subFrameMin, subFrameMax); 0771 break; 0772 } 0773 } 0774 0775 template <typename T> 0776 void StarProfileViewer::getSubFrameMinMax(float *subFrameMin, float *subFrameMax) 0777 { 0778 auto *buffer = reinterpret_cast<T const *>(imageData->getImageBuffer()); 0779 T min = std::numeric_limits<T>::max(); 0780 T max = std::numeric_limits<T>::min(); 0781 int width = imageData->width(); 0782 for (int y = subFrame.y(); y < subFrame.y() + subFrame.height(); y++) 0783 { 0784 for (int x = subFrame.x(); x < subFrame.x() + subFrame.width(); x++) 0785 { 0786 if( x > 0 && x < imageData->width() && y > 0 && y < imageData->height()) 0787 { 0788 min = qMin(min, *(buffer + x + y * width)); 0789 max = qMax(max, *(buffer + x + y * width)); 0790 } 0791 } 0792 } 0793 0794 *subFrameMin = min; 0795 *subFrameMax = max; 0796 } 0797 0798 template <typename T> 0799 float StarProfileViewer::getImageDataValue(int x, int y) 0800 { 0801 if(!imageData) 0802 return 0; 0803 auto *buffer = reinterpret_cast<T const *>(imageData->getImageBuffer()); 0804 return (float) buffer[y * imageData->width() + x]; 0805 } 0806 0807 0808 0809 float StarProfileViewer::getImageDataValue(int x, int y) 0810 { 0811 switch (imageData->getStatistics().dataType) 0812 { 0813 case TBYTE: 0814 return getImageDataValue<uint8_t>(x, y); 0815 break; 0816 0817 case TSHORT: 0818 return getImageDataValue<int16_t>(x, y); 0819 break; 0820 0821 case TUSHORT: 0822 return getImageDataValue<uint16_t>(x, y); 0823 break; 0824 0825 case TLONG: 0826 return getImageDataValue<int32_t>(x, y); 0827 break; 0828 0829 case TULONG: 0830 return getImageDataValue<uint32_t>(x, y); 0831 break; 0832 0833 case TFLOAT: 0834 return getImageDataValue<float>(x, y); 0835 break; 0836 0837 case TLONGLONG: 0838 return getImageDataValue<int64_t>(x, y); 0839 break; 0840 0841 case TDOUBLE: 0842 return getImageDataValue<double>(x, y); 0843 break; 0844 0845 default: 0846 return 0; 0847 break; 0848 } 0849 } 0850 0851 void StarProfileViewer::toggleSlice() 0852 { 0853 if(m_graph->selectionMode() == QAbstract3DGraph::SelectionItemAndRow || m_graph->selectionMode() == QAbstract3DGraph::SelectionItemAndColumn) 0854 { 0855 0856 if(m_graph->scene()->isSlicingActive()) 0857 { 0858 m_graph->scene()->setSlicingActive(false); 0859 } 0860 else 0861 { 0862 QPoint selectedBar = m_graph->selectedSeries() 0863 ? m_graph->selectedSeries()->selectedBar() 0864 : QBar3DSeries::invalidSelectionPosition(); 0865 if (selectedBar != QBar3DSeries::invalidSelectionPosition()) 0866 m_graph->scene()->setSlicingActive(true); 0867 } 0868 } 0869 } 0870 0871 void StarProfileViewer::updateVerticalAxis() 0872 { 0873 float blackPoint = convertFromSliderValue(blackPointSlider->value()); 0874 float whitePoint = convertFromSliderValue(whitePointSlider->value()); 0875 m_pixelValueAxis->setRange(blackPoint, whitePoint); 0876 maxValue->setText(i18n("Max: %1", roundf(whitePoint * 100) / 100)); 0877 minValue->setText(i18n("Min: %1", roundf(blackPoint * 100) / 100)); 0878 } 0879 0880 void StarProfileViewer::updateHFRandPeakSelection() 0881 { 0882 m_graph->removeCustomItems(); 0883 0884 reportBox->setText(""); 0885 QString reportString = ""; 0886 0887 //Removes all the stars from the combo box. 0888 while(zoomView->count() > 7) 0889 zoomView->removeItem(7); 0890 0891 for (int i = 0; i < starCenters.count(); i++) 0892 { 0893 int x = starCenters[i]->x; 0894 int row = x - subFrame.x(); 0895 int y = starCenters[i]->y; 0896 int col = subFrame.height() - (y - subFrame.y()); 0897 if(subFrame.contains(x,y)){ 0898 double newHFR = imageData->getHFR(x,y); 0899 int value = getImageDataValue(x, y); 0900 QCustom3DLabel *label = new QCustom3DLabel(); 0901 label->setFacingCamera(true); 0902 QString labelString = i18n("Star %1: ", i + 1); 0903 if(showCoordinates->isChecked()) 0904 { 0905 labelString = labelString + i18n("(%1, %2) ", x + 1, y + 1); 0906 } 0907 if(HFRReport->isChecked()) 0908 { 0909 labelString = labelString + i18n("HFR: %1 ", roundf(newHFR * 100) / 100); 0910 } 0911 if(showPeakValues->isChecked()) 0912 { 0913 labelString = labelString + i18n("Peak: %1", value); 0914 0915 } 0916 if(showCoordinates->isChecked() || HFRReport->isChecked() || showPeakValues->isChecked()) 0917 { 0918 if (!reportString.isEmpty()) 0919 reportString += '\n'; 0920 0921 reportString += labelString; 0922 label->setText(labelString); 0923 label->setPosition(QVector3D(row, value, col)); 0924 label->setScaling(QVector3D(1.0f, 1.0f, 1.0f)); 0925 m_graph->addCustomItem(label); 0926 } 0927 //Adds this star to the combo box. 0928 zoomView->addItem(i18n("Star %1", i + 1)); 0929 } 0930 } 0931 if (!reportString.isEmpty()) 0932 { 0933 reportBox->setText(reportString); 0934 } 0935 } 0936 0937 void StarProfileViewer::updateColor(int selection) 0938 { 0939 switch (selection) { 0940 case 0: 0941 setGreenToRedGradient(); 0942 break; 0943 0944 case 1: 0945 setBlackToYellowGradient(); 0946 break; 0947 0948 default: 0949 break; 0950 } 0951 } 0952 0953 void StarProfileViewer::setBlackToYellowGradient() 0954 { 0955 QLinearGradient gr; 0956 gr.setColorAt(0.0, Qt::black); 0957 gr.setColorAt(0.33, Qt::blue); 0958 gr.setColorAt(0.67, Qt::red); 0959 gr.setColorAt(1.0, Qt::yellow); 0960 0961 QLinearGradient highGr; 0962 highGr.setColorAt(0.0, Qt::yellow); 0963 highGr.setColorAt(1.0, Qt::yellow); 0964 0965 QLinearGradient sinHighGr; 0966 sinHighGr.setColorAt(0.0, Qt::red); 0967 sinHighGr.setColorAt(1.0, Qt::red); 0968 0969 m_3DPixelSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient); 0970 m_3DPixelSeries->setBaseGradient(gr); 0971 m_3DPixelSeries->setSingleHighlightGradient(sinHighGr); 0972 m_3DPixelSeries->setMultiHighlightGradient(highGr); 0973 } 0974 0975 void StarProfileViewer::setGreenToRedGradient() 0976 { 0977 QLinearGradient gr; 0978 gr.setColorAt(0.0, Qt::darkGreen); 0979 gr.setColorAt(0.5, Qt::yellow); 0980 gr.setColorAt(0.8, Qt::red); 0981 gr.setColorAt(1.0, Qt::darkRed); 0982 0983 QLinearGradient highGr; 0984 highGr.setColorAt(0.0, Qt::black); 0985 highGr.setColorAt(1.0, Qt::black); 0986 0987 QLinearGradient sinHighGr; 0988 sinHighGr.setColorAt(0.0, Qt::red); 0989 sinHighGr.setColorAt(1.0, Qt::red); 0990 0991 m_3DPixelSeries->setBaseGradient(gr); 0992 m_3DPixelSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient); 0993 m_3DPixelSeries->setSingleHighlightGradient(sinHighGr); 0994 m_3DPixelSeries->setMultiHighlightGradient(highGr); 0995 } 0996 0997 //Multiplying by 1000000 will take care of preserving decimals in an int slider 0998 //The sqrt function makes the slider non-linear, emphasising the lower values 0999 //Note that it is actually multiplying the number on the slider by 1000 or so since it is square rooted. 1000 1001 int StarProfileViewer::convertToSliderValue(float value) 1002 { 1003 return (int) qSqrt((value * 1000000.0)); 1004 } 1005 1006 float StarProfileViewer::convertFromSliderValue(int value) 1007 { 1008 return qPow((float)value,2) / 1000000.0; 1009 } 1010