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{
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{
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 setRange(int min, int max)
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 removeItem(int index)
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)
void setText(const QString &)
bool setAlignment(QLayout *l, Qt::Alignment alignment)
iterator begin()
qsizetype count() const const
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 contains(const QPoint &point, bool proper) const const
int height() const const
int width() const const
int x() const const
int y() const const
void setTickInterval(int ti)
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 setEnabled(bool)
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-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:15:12 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.