Kstars

starprofileviewer.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Robert Lancaster <rlancaste@gmail.com>
3
4 Based on the QT Surface Example https://doc.qt.io/qt-5.9/qtdatavisualization-surface-example.html
5 and the QT Bars Example https://doc-snapshots.qt.io/qt5-5.9/qtdatavisualization-bars-example.html
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "starprofileviewer.h"
11#include <KLocalizedString>
12
13#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
14using namespace QtDataVisualization;
15#endif
16
17StarProfileViewer::StarProfileViewer(QWidget *parent) : QDialog(parent)
18{
19
20#ifdef Q_OS_MACOS
21 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
22#endif
23
24 m_graph = new Q3DBars();
25 m_pixelValueAxis = m_graph->valueAxis();
26 m_xPixelAxis = m_graph->columnAxis();
27 m_yPixelAxis = m_graph->rowAxis();
28
29 m_pixelValueAxis->setTitle(i18n("Pixel Values"));
30 m_pixelValueAxis->setLabelAutoRotation(30.0f);
31 m_pixelValueAxis->setTitleVisible(true);
32
33 m_xPixelAxis->setTitle(i18n("Horizontal"));
34 m_xPixelAxis->setLabelAutoRotation(30.0f);
35 m_xPixelAxis->setTitleVisible(true);
36 m_yPixelAxis->setTitle(i18n("Vertical"));
37 m_yPixelAxis->setLabelAutoRotation(30.0f);
38 m_yPixelAxis->setTitleVisible(true);
39
40 m_3DPixelSeries = new QBar3DSeries;
41
42 m_3DPixelSeries->setMesh(QAbstract3DSeries::MeshBevelBar);
43 m_graph->addSeries(m_3DPixelSeries);
44
45 m_graph->activeTheme()->setLabelBackgroundEnabled(false);
46
47 QWidget *container = QWidget::createWindowContainer(m_graph);
48
49 if (!m_graph->hasContext()) {
50 QMessageBox msgBox;
51 msgBox.setText(i18n("Couldn't initialize the OpenGL context."));
52 msgBox.exec();
53 return;
54 }
55
56 QSize screenSize = m_graph->screen()->size();
57 container->setMinimumSize(QSize(300, 500));
58 container->setMaximumSize(screenSize);
61
62 this->setWindowTitle(i18nc("@title:window", "View Star Profile"));
63
64 QVBoxLayout *mainLayout = new QVBoxLayout(this);
65 QHBoxLayout *topLayout = new QHBoxLayout();
66 QHBoxLayout *controlsLayout = new QHBoxLayout();
67 QWidget* rightWidget = new QWidget();
68 rightWidget->setVisible(false);
69 QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget);
70 QGridLayout *sliderLayout = new QGridLayout();
71
72 topLayout->addWidget(container, 1);
73 topLayout->addWidget(rightWidget);
74 mainLayout->addLayout(topLayout);
75 mainLayout->addLayout(controlsLayout);
76 controlsLayout->setAlignment(Qt::AlignLeft);
77
78 maxValue=new QLabel(this);
79 maxValue->setToolTip(i18n("Maximum Value on the graph"));
80 cutoffValue=new QLabel(this);
81 cutoffValue->setToolTip(i18n("Cuttoff Maximum for eliminating hot pixels and bright stars."));
82
83 QCheckBox *toggleEnableCutoff= new QCheckBox(this);
84 toggleEnableCutoff->setToolTip(i18n("Enable or Disable the Max Value Cutoff"));
85 toggleEnableCutoff->setText(i18n("Toggle Cutoff"));
86 toggleEnableCutoff->setChecked(false);
87
88 blackPointSlider=new QSlider( Qt::Vertical, this);
89 blackPointSlider->setToolTip(i18n("Sets the Minimum Value on the graph"));
90 sliderLayout->addWidget(blackPointSlider,0,0);
91 sliderLayout->addWidget(new QLabel(i18n("Min")),1,0);
92
93 whitePointSlider=new QSlider( Qt::Vertical, this);
94 whitePointSlider->setToolTip(i18n("Sets the Maximum Value on the graph"));
95 sliderLayout->addWidget(whitePointSlider,0,1);
96 sliderLayout->addWidget(new QLabel(i18n("Max")),1,1);
97
98 cutoffSlider=new QSlider( Qt::Vertical, this);
99 cutoffSlider->setToolTip(i18n("Sets the Cuttoff Maximum for eliminating hot pixels and bright stars."));
100 sliderLayout->addWidget(cutoffSlider,0,2);
101 sliderLayout->addWidget(new QLabel(i18n("Cut")),1,2);
102 cutoffSlider->setEnabled(false);
103
104 minValue = new QLabel(this);
105 minValue->setToolTip(i18n("Minimum Value on the graph"));
106
107 autoScale = new QCheckBox(this);
108 autoScale->setText(i18n("AutoScale"));
109 autoScale->setToolTip(i18n("Automatically scales the sliders for the subFrame.\nUncheck to leave them unchanged when you pan around."));
110 autoScale->setChecked(true);
111
112 showScaling = new QPushButton(this);
113 showScaling->setIcon(QIcon::fromTheme("transform-move-vertical"));
114 showScaling->setCheckable(true);
115 showScaling->setMaximumSize(22, 22);
116 showScaling->setAttribute(Qt::WA_LayoutUsesWidgetRect);
117 showScaling->setToolTip(i18n("Hides and shows the scaling side panel"));
118 showScaling->setChecked(false);
119
120 rightLayout->addWidget(toggleEnableCutoff);
121 rightLayout->addWidget(cutoffValue);
122 rightLayout->addWidget(maxValue);
123 rightLayout->addLayout(sliderLayout);
124 rightLayout->addWidget(minValue);
125 rightLayout->addWidget(autoScale);
126
127 selectionType = new QComboBox(this);
128 selectionType->setToolTip(i18n("Changes the type of selection"));
129 selectionType->addItem(i18n("Item"));
130 selectionType->addItem(i18n("Horizontal"));
131 selectionType->addItem(i18n("Vertical"));
132 selectionType->setCurrentIndex(0);
133
134 sliceB = new QPushButton(this);
135 sliceB->setIcon(QIcon::fromTheme("view-object-histogram-linear"));
136 sliceB->setCheckable(true);
137 sliceB->setMaximumSize(22, 22);
138 sliceB->setAttribute(Qt::WA_LayoutUsesWidgetRect);
139 sliceB->setToolTip(i18n("Toggles the slice view when horizontal or vertical items are selected"));
140 sliceB->setCheckable(true);
141 sliceB->setChecked(false);
142 sliceB->setEnabled(false);
143 sliceB->setDefault(false);
144
145 showCoordinates = new QPushButton(this);
146 showCoordinates->setIcon(QIcon::fromTheme("coordinate"));
147 showCoordinates->setCheckable(true);
148 showCoordinates->setMaximumSize(22, 22);
149 showCoordinates->setAttribute(Qt::WA_LayoutUsesWidgetRect);
150 showCoordinates->setToolTip(i18n("Shows the x, y coordinates of star centers in the frame"));
151 showCoordinates->setChecked(false);
152
153 HFRReport = new QPushButton(this);
154 HFRReport->setToolTip(i18n("Shows the HFR of stars in the frame"));
155 HFRReport->setIcon(QIcon::fromTheme("tool-measure"));
156 HFRReport->setCheckable(true);
157 HFRReport->setMaximumSize(22, 22);
158 HFRReport->setAttribute(Qt::WA_LayoutUsesWidgetRect);
159 HFRReport->setChecked(true);
160
161 reportBox = new QLabel(this);
162
163 showPeakValues = new QPushButton(this);
164 showPeakValues->setIcon(QIcon::fromTheme("kruler-east"));
165 showPeakValues->setCheckable(true);
166 showPeakValues->setMaximumSize(22, 22);
167 showPeakValues->setAttribute(Qt::WA_LayoutUsesWidgetRect);
168 showPeakValues->setToolTip(i18n("Shows the peak values of star centers in the frame"));
169 showPeakValues->setChecked(true);
170
171 sampleSize = new QComboBox(this);
172 sampleSize->setToolTip(i18n("Changes the sample size shown in the graph"));
173 sampleSize->addItem(QString::number(16));
174 sampleSize->addItem(QString::number(32));
175 sampleSize->addItem(QString::number(64));
176 sampleSize->addItem(QString::number(128));
177 sampleSize->addItem(QString::number(256));
178 sampleSize->addItem(QString::number(512));
179 sampleSize->setCurrentIndex(3);
180 sampleSize->setVisible(false);
181
182 zoomView = new QComboBox(this);
183 zoomView->setToolTip(i18n("Zooms the view to preset locations."));
184 zoomView->addItem(i18n("ZoomTo"));
185 zoomView->addItem(i18n("Front"));
186 zoomView->addItem(i18n("Front High"));
187 zoomView->addItem(i18n("Overhead"));
188 zoomView->addItem(i18n("Iso. L"));
189 zoomView->addItem(i18n("Iso. R"));
190 zoomView->addItem(i18n("Selected"));
191 zoomView->setCurrentIndex(0);
192
193 QPushButton *selectorsVisible = new QPushButton(this);
194 selectorsVisible->setIcon(QIcon::fromTheme("adjustlevels"));
195 selectorsVisible->setCheckable(true);
196 selectorsVisible->setMaximumSize(22, 22);
197 selectorsVisible->setAttribute(Qt::WA_LayoutUsesWidgetRect);
198 selectorsVisible->setToolTip(i18n("Hides and shows the Vertical and Horizontal Selection Sliders"));
199 selectorsVisible->setChecked(false);
200
201 controlsLayout->addWidget(sampleSize);
202 controlsLayout->addWidget(selectionType);
203 controlsLayout->addWidget(selectorsVisible);
204 controlsLayout->addWidget(sliceB);
205 controlsLayout->addWidget(showScaling);
206 //bottomLayout->addWidget(barSpacing);
207 controlsLayout->addWidget(zoomView);
208 //bottomLayout->addWidget(color);
209 controlsLayout->addWidget(showCoordinates);
210 controlsLayout->addWidget(HFRReport);
211 controlsLayout->addWidget(showPeakValues);
212 controlsLayout->addWidget(reportBox);
213
214 QWidget *bottomSliderWidget= new QWidget(this);
215 QGridLayout *bottomSliders = new QGridLayout(bottomSliderWidget);
216 bottomSliderWidget->setLayout(bottomSliders);
217 mainLayout->addWidget(bottomSliderWidget);
218 bottomSliderWidget->setVisible(false);
219
220 verticalSelector = new QSlider(Qt::Horizontal, this);
221 verticalSelector->setToolTip(i18n("Selects the Vertical Value"));
222 horizontalSelector = new QSlider(Qt::Horizontal, this);
223 horizontalSelector->setToolTip(i18n("Selects the Horizontal Value"));
224
225 bottomSliders->addWidget(new QLabel(i18n("Vertical: ")), 0, 0);
226 bottomSliders->addWidget(verticalSelector, 0, 1);
227 bottomSliders->addWidget(new QLabel(i18n("Horizontal: ")), 1, 0);
228 bottomSliders->addWidget(horizontalSelector, 1, 1);
229
230 QWidget *bottomControlsWidget= new QWidget(this);
231 QHBoxLayout *bottomControlLayout = new QHBoxLayout(bottomControlsWidget);
232 mainLayout->addWidget(bottomControlsWidget);\
233 bottomControlsWidget->setVisible(false);
234
235 exploreMode = new QPushButton(this);
236 exploreMode->setIcon(QIcon::fromTheme("visibility"));
237 exploreMode->setCheckable(true);
238 exploreMode->setMaximumSize(22, 22);
239 exploreMode->setAttribute(Qt::WA_LayoutUsesWidgetRect);
240 exploreMode->setToolTip(i18n("Zooms automatically as the sliders change"));
241 exploreMode->setChecked(true);
242
243 QDial *barSpacing=new QDial(this);
244 barSpacing->setMinimum(0);
245 barSpacing->setMaximum(100);
246 barSpacing->setValue(50);
247 barSpacing->setMaximumSize(32, 32);
248 barSpacing->setWrapping(false);
249 m_graph->setBarSpacing(QSizeF(0.5,0.5));
250
251 QComboBox *color = new QComboBox(this);
252 color->setToolTip(i18n("Changes the color scheme"));
253
254 QLinearGradient grGtoR(50, 1, 0, 0);
255 grGtoR.setColorAt(1.0, Qt::darkGreen);
256 grGtoR.setColorAt(0.5, Qt::yellow);
257 grGtoR.setColorAt(0.2, Qt::red);
258 grGtoR.setColorAt(0.0, Qt::darkRed);
259 QPixmap pm(50, 10);
260 QPainter pmp(&pm);
261 pmp.setPen(Qt::NoPen);
262 pmp.setBrush(QBrush(grGtoR));
263 pmp.drawRect(0, 0, 50, 10);
264 color->addItem("");
265 color->setItemIcon(0,QIcon(pm));
266
267 QLinearGradient grBtoY(50, 1, 0, 0);
268 grBtoY.setColorAt(1.0, Qt::black);
269 grBtoY.setColorAt(0.67, Qt::blue);
270 grBtoY.setColorAt(0.33, Qt::red);
271 grBtoY.setColorAt(0.0, Qt::yellow);
272 pmp.setBrush(QBrush(grBtoY));
273 pmp.drawRect(0, 0, 50, 10);
274 color->addItem("");
275 color->setItemIcon(1,QIcon(pm));
276
277 color->setIconSize(QSize(50, 10));
278 color->setCurrentIndex(0);
279 color->setMaximumWidth(80);
280
281 pixelReport = new QLabel("", bottomControlsWidget);
282
283 bottomControlLayout->addWidget(exploreMode);
284 bottomControlLayout->addWidget(barSpacing);
285 bottomControlLayout->addWidget(color);
286 bottomControlLayout->addWidget(pixelReport);
287
288 QObject::connect(selectionType, SIGNAL(currentIndexChanged(int)),
289 this, SLOT(changeSelectionType(int)));
290 QObject::connect(zoomView, SIGNAL(currentIndexChanged(int)),
291 this, SLOT(zoomViewTo(int)));
293 this, &StarProfileViewer::toggleSlice);
294 QObject::connect(showCoordinates, &QCheckBox::toggled,
295 this, &StarProfileViewer::updateHFRandPeakSelection);
297 this, &StarProfileViewer::updateHFRandPeakSelection);
298 QObject::connect(showPeakValues, &QCheckBox::toggled,
299 this, &StarProfileViewer::updateHFRandPeakSelection);
300 QObject::connect(blackPointSlider, &QSlider::valueChanged,
301 this, &StarProfileViewer::updateVerticalAxis);
302 QObject::connect(whitePointSlider, &QSlider::valueChanged,
303 this, &StarProfileViewer::updateVerticalAxis);
305 this, &StarProfileViewer::updateDisplayData);
307 this, &StarProfileViewer::updateScale);
309 rightWidget, &QWidget::setVisible);
310 QObject::connect(sampleSize, SIGNAL(currentIndexChanged(QString)),
311 this, SLOT(updateSampleSize(QString)));
312 QObject::connect(color, SIGNAL(currentIndexChanged(int)),
313 this, SLOT(updateColor(int)));
314 QObject::connect(verticalSelector, &QSlider::valueChanged,
315 this, &StarProfileViewer::changeSelection);
316 QObject::connect(horizontalSelector, &QSlider::valueChanged,
317 this, &StarProfileViewer::changeSelection);
318 QObject::connect(selectorsVisible, &QCheckBox::toggled,
319 bottomSliderWidget, &QWidget::setVisible);
320 QObject::connect(selectorsVisible, &QCheckBox::toggled,
321 bottomControlsWidget, &QWidget::setVisible);
322 QObject::connect(toggleEnableCutoff, &QCheckBox::toggled,
323 this, &StarProfileViewer::toggleCutoffEnabled);
324 QObject::connect(m_3DPixelSeries, &QBar3DSeries::selectedBarChanged,
325 this, &StarProfileViewer::updateSelectorBars);
327 this, &StarProfileViewer::updateBarSpacing);
328
329 m_graph->activeTheme()->setType(Q3DTheme::Theme(3)); //Stone Moss
330
331 setGreenToRedGradient();
332
333 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
334 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
335 m_graph->scene()->activeCamera()->setZoomLevel(110);
336
337 //Note: This is to prevent a button from being called the default button
338 //and then executing when the user hits the enter key such as when on a Text Box
339 #ifdef Q_OS_MACOS
340 QList<QPushButton *> qButtons = findChildren<QPushButton *>();
341 for (auto &button : qButtons)
342 button->setAutoDefault(false);
343 #endif
344
345 show();
346}
347
348StarProfileViewer::~StarProfileViewer()
349{
350 delete m_graph;
351}
352
353void StarProfileViewer::loadData(QSharedPointer<FITSData> data, QRect sub, QList<Edge *> centers)
354{
355 if(data)
356 {
357 imageData = data;
358 subFrame=sub;
359 starCenters=centers;
360
361 switch (data->getStatistics().dataType)
362 {
363 case TBYTE:
364 loadDataPrivate<uint8_t>();
365 break;
366
367 case TSHORT:
368 loadDataPrivate<int16_t>();
369 break;
370
371 case TUSHORT:
372 loadDataPrivate<uint16_t>();
373 break;
374
375 case TLONG:
376 loadDataPrivate<int32_t>();
377 break;
378
379 case TULONG:
380 loadDataPrivate<uint32_t>();
381 break;
382
383 case TFLOAT:
384 loadDataPrivate<float>();
385 break;
386
387 case TLONGLONG:
388 loadDataPrivate<int64_t>();
389 break;
390
391 case TDOUBLE:
392 loadDataPrivate<double>();
393 break;
394 }
395
396 updateScale();
397
398 // Add data to the data proxy (the data proxy assumes ownership of it)
399 // We will retain a copy of the data set so that we can update the display
400 updateDisplayData();
401
402 updateHFRandPeakSelection();
403
404 horizontalSelector->setRange(0, subFrame.width()-1);
405 verticalSelector->setRange(0, subFrame.width()-1); //Width and height are the same
406 }
407}
408
409template <typename T>
410void StarProfileViewer::loadDataPrivate()
411{
412 // Create data arrays
413 dataSet = new QBarDataArray;
414 QBarDataRow *dataRow;
415 dataSet->reserve(subFrame.height());
416 QStringList rowLabels;
417 QStringList columnLabels;
418
419 auto *buffer = reinterpret_cast<T const *>(imageData->getImageBuffer());
420 int width = imageData->width();
421
422 for (int j = subFrame.y(); j < subFrame.y() + subFrame.height(); j++)
423 {
424 if( j % 10 == 0 )
425 rowLabels << QString::number(j);
426 else
427 rowLabels << "";
428 dataRow = new QBarDataRow(subFrame.width());
429 int x = 0;
430 for (int i = subFrame.x(); i < subFrame.x() + subFrame.width(); i++)
431 {
432 if( i % 10 == 0 )
433 columnLabels << QString::number(i);
434 else
435 columnLabels << "";
436 if( i > 0 && i < imageData->width() && j > 0 && j < imageData->height())
437 (*dataRow)[x].setValue(*(buffer + i + j * width));
438 x++;
439 }
440 dataSet->insert(0, dataRow); //Note the row axis is displayed in the opposite direction of the y axis in the image.
441 }
442
443 std::reverse(rowLabels.begin(), rowLabels.end());
444
445 m_3DPixelSeries->dataProxy()->setRowLabels(rowLabels);
446 m_3DPixelSeries->dataProxy()->setColumnLabels(columnLabels);
447}
448
449void StarProfileViewer::toggleCutoffEnabled(bool enable)
450{
451 cutoffSlider->setEnabled(enable);
452 cutOffEnabled = enable;
453 updateDisplayData();
454}
455
456void StarProfileViewer::updateScale()
457{
458
459 //We need to disconnect these so that changing their ranges doesn't affect things
461 this, &StarProfileViewer::updateVerticalAxis);
463 this, &StarProfileViewer::updateVerticalAxis);
465 this, &StarProfileViewer::updateDisplayData);
466
467 float subFrameMin, subFrameMax;
468 double dataMin, dataMax;
469 float min, max;
470 getSubFrameMinMax(&subFrameMin, &subFrameMax, &dataMin, &dataMax);
471
472 int sliderDataMin = convertToSliderValue(dataMin) - 1; //Expands the slider range a little beyond the max and min values
473 int sliderDataMax = convertToSliderValue(dataMax) + 1;
474
475 if(autoScale->isChecked())
476 {
477 min = subFrameMin;
478 max = subFrameMax;
479 int sliderMin = convertToSliderValue(min) - 1; //Expands the slider range a little beyond the max and min values
480 int sliderMax = convertToSliderValue(max) + 1;
481 blackPointSlider->setRange(sliderMin, sliderMax);
482 blackPointSlider->setTickInterval((sliderMax - sliderMin) / 100);
483 whitePointSlider->setRange(sliderMin, sliderMax);
484 whitePointSlider->setTickInterval((sliderMax - sliderMin) / 100);
485 cutoffSlider->setRange(sliderMin, sliderDataMax);
486 cutoffSlider->setTickInterval((sliderDataMax - sliderMin) / 100);
487 blackPointSlider->setValue(sliderMin);
488 whitePointSlider->setValue(sliderMax);
489 cutoffSlider->setValue(sliderDataMax);
490 }
491 else
492 {
493 min = convertFromSliderValue(blackPointSlider->value());
494 max = convertFromSliderValue(whitePointSlider->value());
495 blackPointSlider->setRange(sliderDataMin, sliderDataMax);
496 blackPointSlider->setTickInterval((sliderDataMax - sliderDataMin) / 100);
497 whitePointSlider->setRange(sliderDataMin, sliderDataMax);
498 whitePointSlider->setTickInterval((sliderDataMax - sliderDataMin) / 100);
499 cutoffSlider->setRange(sliderDataMin, sliderDataMax);
500 cutoffSlider->setTickInterval((sliderDataMax - sliderDataMin) / 100);
501
502 }
503 m_pixelValueAxis->setRange(min, max);
504
505 if(cutOffEnabled)
506 cutoffValue->setText(i18n("Cut: %1", roundf(convertFromSliderValue(cutoffSlider->value()) * 100) / 100));
507 else
508 cutoffValue->setText("Cut Disabled");
509
510 if(max < 10 )
511 {
512 m_pixelValueAxis->setLabelFormat(QString(QStringLiteral("%.3f ")));
513 m_3DPixelSeries->setItemLabelFormat(QString(QStringLiteral("%.3f ")));
514 maxValue->setText(i18n("Max: %1", roundf(max * 100) / 100));
515 minValue->setText(i18n("Min: %1", roundf(min * 100) / 100));
516 }
517 else
518 {
519 m_pixelValueAxis->setLabelFormat(QString(QStringLiteral("%.0f ")));
520 m_3DPixelSeries->setItemLabelFormat(QString(QStringLiteral("%.0f ")));
521 maxValue->setText(i18n("Max: %1", max));
522 minValue->setText(i18n("Min: %1", min));
523 }
524
525 QObject::connect(blackPointSlider, &QSlider::valueChanged,
526 this, &StarProfileViewer::updateVerticalAxis);
527 QObject::connect(whitePointSlider, &QSlider::valueChanged,
528 this, &StarProfileViewer::updateVerticalAxis);
530 this, &StarProfileViewer::updateDisplayData);
531}
532
533void StarProfileViewer::updateBarSpacing(int value)
534{
535 float spacing = (float)value/100.0;
536 m_graph->setBarSpacing(QSizeF(spacing, spacing));
537}
538
539void StarProfileViewer::zoomViewTo(int where)
540{
541 if(where > 6) //One of the star centers
542 {
543 int star = where - 7;
544 int x = starCenters[star]->x - subFrame.x();
545 int y = subFrame.height() - (starCenters[star]->y - subFrame.y());
546 m_graph->primarySeries()->setSelectedBar(QPoint( y , x )); //Note row, column y, x
547 where = 6; //This is so it will zoom to the target.
548 }
549
550 switch (where) {
551 case 0: //Zoom To
552 break;
553
554 case 1: //Front
555 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
556 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
557 m_graph->scene()->activeCamera()->setZoomLevel(110);
558 zoomView->setCurrentIndex(0);
559 break;
560
561 case 2: //Front High
562 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFrontHigh);
563 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
564 m_graph->scene()->activeCamera()->setZoomLevel(110);
565 zoomView->setCurrentIndex(0);
566 break;
567
568 case 3: //Overhead
569 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetDirectlyAbove);
570 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
571 m_graph->scene()->activeCamera()->setZoomLevel(110);
572 zoomView->setCurrentIndex(0);
573 break;
574
575 case 4: //Isometric L
576 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeftHigh);
577 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
578 m_graph->scene()->activeCamera()->setZoomLevel(110);
579 zoomView->setCurrentIndex(0);
580 break;
581
582 case 5: //Isometric R
583 m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricRightHigh);
584 m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
585 m_graph->scene()->activeCamera()->setZoomLevel(110);
586 zoomView->setCurrentIndex(0);
587 break;
588
589 case 6: //Selected Item
590 {
591 QPoint selectedBar = m_graph->selectedSeries()
592 ? m_graph->selectedSeries()->selectedBar()
593 : QBar3DSeries::invalidSelectionPosition();
594 if (selectedBar != QBar3DSeries::invalidSelectionPosition())
595 {
596 QVector3D target;
597 float xMin = m_graph->columnAxis()->min();
598 float xRange = m_graph->columnAxis()->max() - xMin;
599 float zMin = m_graph->rowAxis()->min();
600 float zRange = m_graph->rowAxis()->max() - zMin;
601 target.setX((selectedBar.y() - xMin) / xRange * 2.0f - 1.0f);
602 target.setZ((selectedBar.x() - zMin) / zRange * 2.0f - 1.0f);
603
604 qreal endAngleX = qAtan(qreal(target.z() / target.x())) / M_PI * -180.0 + 90.0;
605 if (target.x() > 0.0f)
606 endAngleX -= 180.0f;
607 float barValue = m_graph->selectedSeries()->dataProxy()->itemAt(selectedBar.x(),
608 selectedBar.y())->value();
609 float endAngleY = 60.0f;
610 float zoom = 150 * 1/qSqrt(barValue / convertFromSliderValue(whitePointSlider->value()));
611 m_graph->scene()->activeCamera()->setCameraPosition(endAngleX, endAngleY, zoom);
612 m_graph->scene()->activeCamera()->setTarget(target);
613
614
615 }
616 zoomView->setCurrentIndex(0);
617 break;
618 }
619
620
621 default:
622 zoomView->setCurrentIndex(0);
623 break;
624 }
625}
626
627void StarProfileViewer::changeSelectionType(int type)
628{
629 switch (type) {
630 case 0:
631 m_graph->setSelectionMode(QAbstract3DGraph::SelectionItem);
632 m_graph->scene()->setSlicingActive(false);
633 sliceB->setEnabled(false);
634 break;
635
636 case 1:
637 m_graph->setSelectionMode(QAbstract3DGraph::SelectionItemAndRow);
638 sliceB->setEnabled(true);
639 break;
640
641 case 2:
642 m_graph->setSelectionMode(QAbstract3DGraph::SelectionItemAndColumn);
643 sliceB->setEnabled(true);
644 break;
645
646 default:
647 break;
648 }
649}
650
651void StarProfileViewer::changeSelection()
652{
653 int x = horizontalSelector->value();
654 int y = verticalSelector->value();
655 m_graph->primarySeries()->setSelectedBar(QPoint( y , x )); //Note row, column y, x
656 if(exploreMode->isChecked())
657 zoomViewTo(6); //Zoom to SelectedItem
658 updatePixelReport();
659}
660
661void StarProfileViewer::updatePixelReport()
662{
663 int x = horizontalSelector->value();
664 int y = verticalSelector->value();
665 //They need to be shifted to the location of the subframe
666 x += subFrame.x();
667 y = (subFrame.height() - 1 - y) + subFrame.y(); //Note: Y is in reverse order on the graph.
668 float barValue = getImageDataValue(x, y);
669 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
670
671}
672
673
674void StarProfileViewer::updateSelectorBars(QPoint position)
675{
676 //Note that we need to disconnect and then reconnect to avoid triggering changeSelection
678 this, &StarProfileViewer::changeSelection);
679 QObject::disconnect(horizontalSelector, &QSlider::valueChanged,
680 this, &StarProfileViewer::changeSelection);
681
682 //Note row, column y, x
683 verticalSelector->setValue(position.x());
684 horizontalSelector->setValue(position.y());
685 updatePixelReport();
686
687 QObject::connect(verticalSelector, &QSlider::valueChanged,
688 this, &StarProfileViewer::changeSelection);
689 QObject::connect(horizontalSelector, &QSlider::valueChanged,
690 this, &StarProfileViewer::changeSelection);
691}
692
693void StarProfileViewer::updateSampleSize(const QString &text)
694{
695 emit sampleSizeUpdated(text.toInt());
696}
697
698void StarProfileViewer::enableTrackingBox(bool enable)
699{
700 sampleSize->setVisible(enable);
701}
702
703void StarProfileViewer::updateDisplayData()
704{
705 if(cutOffEnabled)
706 cutoffValue->setText(i18n("Cut: %1", roundf(convertFromSliderValue(cutoffSlider->value()) * 100) / 100));
707 else
708 cutoffValue->setText(i18n("Cut Disabled"));
709 if(dataSet != nullptr)
710 {
711 QBarDataArray *displayDataSet = new QBarDataArray;
712 displayDataSet->reserve(dataSet->size());
713
714 for (int row = 0; row < dataSet->size(); row++)
715 {
716 QBarDataRow *dataRow = dataSet->at(row);
717 QBarDataRow *newDataRow;
718 newDataRow = new QBarDataRow(dataRow->size());
719 for (int column = 0; column < dataRow->size(); column++)
720 {
721 if(cutOffEnabled && dataRow->value(column).value() > convertFromSliderValue(cutoffSlider->value()))
722 (*newDataRow)[column].setValue(0.0f);
723 else
724 (*newDataRow)[column].setValue(dataRow->value(column).value());
725 }
726 displayDataSet->append(newDataRow);
727
728 }
729 m_3DPixelSeries->dataProxy()->resetArray(displayDataSet); //, m_3DPixelSeries->dataProxy()->rowLabels(), m_3DPixelSeries->dataProxy()->columnLabels()
730 }
731}
732
733void StarProfileViewer::getSubFrameMinMax(float *subFrameMin, float *subFrameMax, double *dataMin, double *dataMax)
734{
735 imageData->getMinMax(dataMin,dataMax);
736
737 //Backwards so that we can find the min and max in subFrame
738 *subFrameMin = *dataMax;
739 *subFrameMax = *dataMin;
740
741 switch (imageData->getStatistics().dataType)
742 {
743 case TBYTE:
744 getSubFrameMinMax<uint8_t>(subFrameMin, subFrameMax);
745 break;
746
747 case TSHORT:
748 getSubFrameMinMax<int16_t>(subFrameMin, subFrameMax);
749 break;
750
751 case TUSHORT:
752 getSubFrameMinMax<uint16_t>(subFrameMin, subFrameMax);
753 break;
754
755 case TLONG:
756 getSubFrameMinMax<int32_t>(subFrameMin, subFrameMax);
757 break;
758
759 case TULONG:
760 getSubFrameMinMax<uint32_t>(subFrameMin, subFrameMax);
761 break;
762
763 case TFLOAT:
764 getSubFrameMinMax<float>(subFrameMin, subFrameMax);
765 break;
766
767 case TLONGLONG:
768 getSubFrameMinMax<int64_t>(subFrameMin, subFrameMax);
769 break;
770
771 case TDOUBLE:
772 getSubFrameMinMax<double>(subFrameMin, subFrameMax);
773 break;
774 }
775}
776
777template <typename T>
778void StarProfileViewer::getSubFrameMinMax(float *subFrameMin, float *subFrameMax)
779{
780 auto *buffer = reinterpret_cast<T const *>(imageData->getImageBuffer());
781 T min = std::numeric_limits<T>::max();
782 T max = std::numeric_limits<T>::min();
783 int width = imageData->width();
784 for (int y = subFrame.y(); y < subFrame.y() + subFrame.height(); y++)
785 {
786 for (int x = subFrame.x(); x < subFrame.x() + subFrame.width(); x++)
787 {
788 if( x > 0 && x < imageData->width() && y > 0 && y < imageData->height())
789 {
790 min = qMin(min, *(buffer + x + y * width));
791 max = qMax(max, *(buffer + x + y * width));
792 }
793 }
794 }
795
796 *subFrameMin = min;
797 *subFrameMax = max;
798}
799
800template <typename T>
801float StarProfileViewer::getImageDataValue(int x, int y)
802{
803 if(!imageData)
804 return 0;
805 auto *buffer = reinterpret_cast<T const *>(imageData->getImageBuffer());
806 return (float) buffer[y * imageData->width() + x];
807}
808
809
810
811float StarProfileViewer::getImageDataValue(int x, int y)
812{
813 switch (imageData->getStatistics().dataType)
814 {
815 case TBYTE:
816 return getImageDataValue<uint8_t>(x, y);
817 break;
818
819 case TSHORT:
820 return getImageDataValue<int16_t>(x, y);
821 break;
822
823 case TUSHORT:
824 return getImageDataValue<uint16_t>(x, y);
825 break;
826
827 case TLONG:
828 return getImageDataValue<int32_t>(x, y);
829 break;
830
831 case TULONG:
832 return getImageDataValue<uint32_t>(x, y);
833 break;
834
835 case TFLOAT:
836 return getImageDataValue<float>(x, y);
837 break;
838
839 case TLONGLONG:
840 return getImageDataValue<int64_t>(x, y);
841 break;
842
843 case TDOUBLE:
844 return getImageDataValue<double>(x, y);
845 break;
846
847 default:
848 return 0;
849 break;
850 }
851}
852
853void StarProfileViewer::toggleSlice()
854{
855 if(m_graph->selectionMode() == QAbstract3DGraph::SelectionItemAndRow || m_graph->selectionMode() == QAbstract3DGraph::SelectionItemAndColumn)
856 {
857
858 if(m_graph->scene()->isSlicingActive())
859 {
860 m_graph->scene()->setSlicingActive(false);
861 }
862 else
863 {
864 QPoint selectedBar = m_graph->selectedSeries()
865 ? m_graph->selectedSeries()->selectedBar()
866 : QBar3DSeries::invalidSelectionPosition();
867 if (selectedBar != QBar3DSeries::invalidSelectionPosition())
868 m_graph->scene()->setSlicingActive(true);
869 }
870 }
871}
872
873void StarProfileViewer::updateVerticalAxis()
874{
875 float blackPoint = convertFromSliderValue(blackPointSlider->value());
876 float whitePoint = convertFromSliderValue(whitePointSlider->value());
877 m_pixelValueAxis->setRange(blackPoint, whitePoint);
878 maxValue->setText(i18n("Max: %1", roundf(whitePoint * 100) / 100));
879 minValue->setText(i18n("Min: %1", roundf(blackPoint * 100) / 100));
880}
881
882void StarProfileViewer::updateHFRandPeakSelection()
883{
884 m_graph->removeCustomItems();
885
886 reportBox->setText("");
887 QString reportString = "";
888
889 //Removes all the stars from the combo box.
890 while(zoomView->count() > 7)
891 zoomView->removeItem(7);
892
893 for (int i = 0; i < starCenters.count(); i++)
894 {
895 int x = starCenters[i]->x;
896 int row = x - subFrame.x();
897 int y = starCenters[i]->y;
898 int col = subFrame.height() - (y - subFrame.y());
899 if(subFrame.contains(x,y)){
900 double newHFR = imageData->getHFR(x,y);
901 int value = getImageDataValue(x, y);
902 QCustom3DLabel *label = new QCustom3DLabel();
903 label->setFacingCamera(true);
904 QString labelString = i18n("Star %1: ", i + 1);
905 if(showCoordinates->isChecked())
906 {
907 labelString = labelString + i18n("(%1, %2) ", x + 1, y + 1);
908 }
909 if(HFRReport->isChecked())
910 {
911 labelString = labelString + i18n("HFR: %1 ", roundf(newHFR * 100) / 100);
912 }
913 if(showPeakValues->isChecked())
914 {
915 labelString = labelString + i18n("Peak: %1", value);
916
917 }
918 if(showCoordinates->isChecked() || HFRReport->isChecked() || showPeakValues->isChecked())
919 {
920 if (!reportString.isEmpty())
921 reportString += '\n';
922
923 reportString += labelString;
924 label->setText(labelString);
925 label->setPosition(QVector3D(row, value, col));
926 label->setScaling(QVector3D(1.0f, 1.0f, 1.0f));
927 m_graph->addCustomItem(label);
928 }
929 //Adds this star to the combo box.
930 zoomView->addItem(i18n("Star %1", i + 1));
931 }
932 }
933 if (!reportString.isEmpty())
934 {
935 reportBox->setText(reportString);
936 }
937}
938
939void StarProfileViewer::updateColor(int selection)
940{
941 switch (selection) {
942 case 0:
943 setGreenToRedGradient();
944 break;
945
946 case 1:
947 setBlackToYellowGradient();
948 break;
949
950 default:
951 break;
952 }
953}
954
955void StarProfileViewer::setBlackToYellowGradient()
956{
957 QLinearGradient gr;
958 gr.setColorAt(0.0, Qt::black);
959 gr.setColorAt(0.33, Qt::blue);
960 gr.setColorAt(0.67, Qt::red);
961 gr.setColorAt(1.0, Qt::yellow);
962
963 QLinearGradient highGr;
964 highGr.setColorAt(0.0, Qt::yellow);
965 highGr.setColorAt(1.0, Qt::yellow);
966
967 QLinearGradient sinHighGr;
968 sinHighGr.setColorAt(0.0, Qt::red);
969 sinHighGr.setColorAt(1.0, Qt::red);
970
971 m_3DPixelSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
972 m_3DPixelSeries->setBaseGradient(gr);
973 m_3DPixelSeries->setSingleHighlightGradient(sinHighGr);
974 m_3DPixelSeries->setMultiHighlightGradient(highGr);
975}
976
977void StarProfileViewer::setGreenToRedGradient()
978{
979 QLinearGradient gr;
980 gr.setColorAt(0.0, Qt::darkGreen);
981 gr.setColorAt(0.5, Qt::yellow);
982 gr.setColorAt(0.8, Qt::red);
983 gr.setColorAt(1.0, Qt::darkRed);
984
985 QLinearGradient highGr;
986 highGr.setColorAt(0.0, Qt::black);
987 highGr.setColorAt(1.0, Qt::black);
988
989 QLinearGradient sinHighGr;
990 sinHighGr.setColorAt(0.0, Qt::red);
991 sinHighGr.setColorAt(1.0, Qt::red);
992
993 m_3DPixelSeries->setBaseGradient(gr);
994 m_3DPixelSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
995 m_3DPixelSeries->setSingleHighlightGradient(sinHighGr);
996 m_3DPixelSeries->setMultiHighlightGradient(highGr);
997}
998
999//Multiplying by 1000000 will take care of preserving decimals in an int slider
1000//The sqrt function makes the slider non-linear, emphasising the lower values
1001//Note that it is actually multiplying the number on the slider by 1000 or so since it is square rooted.
1002
1003int StarProfileViewer::convertToSliderValue(float value)
1004{
1005 return (int) qSqrt((value * 1000000.0));
1006}
1007
1008float StarProfileViewer::convertFromSliderValue(int value)
1009{
1010 return qPow((float)value,2) / 1000000.0;
1011}
1012
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
QString label(StandardShortcut id)
void setCheckable(bool)
void setChecked(bool)
void setIcon(const QIcon &icon)
void setText(const QString &text)
void toggled(bool checked)
void setMaximum(int)
void setMinimum(int)
void setValue(int)
void valueChanged(int value)
void addLayout(QLayout *layout, int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
void setCurrentIndex(int index)
void setIconSize(const QSize &size)
void setItemIcon(int index, const QIcon &icon)
void setWrapping(bool on)
void setColorAt(qreal position, const QColor &color)
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment)
QIcon fromTheme(const QString &name)
bool setAlignment(QLayout *l, Qt::Alignment alignment)
iterator begin()
iterator end()
virtual int exec() override
void setText(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
int x() const const
int y() const const
bool isEmpty() const const
QString number(double n, char format, int precision)
int toInt(bool *ok, int base) const const
AlignLeft
StrongFocus
darkGreen
Vertical
WA_LayoutUsesWidgetRect
void setX(float x)
void setZ(float z)
float x() const const
float z() const const
QWidget * createWindowContainer(QWindow *window, QWidget *parent, Qt::WindowFlags flags)
void setFocusPolicy(Qt::FocusPolicy policy)
void setMaximumSize(const QSize &)
void setMaximumWidth(int maxw)
void setMinimumSize(const QSize &)
void setAttribute(Qt::WidgetAttribute attribute, bool on)
void setLayout(QLayout *layout)
void setSizePolicy(QSizePolicy)
void setToolTip(const QString &)
virtual void setVisible(bool visible)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 21 2025 11:54:28 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.