Warning, file /education/kstars/kstars/ekos/focus/aberrationinspectorplot.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2023 John Evans <john.e.evans.email@googlemail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "aberrationinspectorplot.h" 0008 #include "curvefit.h" 0009 #include "klocalizedstring.h" 0010 0011 namespace Ekos 0012 { 0013 0014 #define DEFAULT_BASIC_FONT_SIZE 10 0015 0016 AberrationInspectorPlot::AberrationInspectorPlot(QWidget *parent) : QCustomPlot (parent) 0017 { 0018 setBackground(QBrush(Qt::black)); 0019 0020 xAxis->setBasePen(QPen(Qt::white, 1)); 0021 yAxis->setBasePen(QPen(Qt::white, 1)); 0022 0023 xAxis->setTickPen(QPen(Qt::white, 1)); 0024 yAxis->setTickPen(QPen(Qt::white, 1)); 0025 0026 xAxis->setSubTickPen(QPen(Qt::white, 1)); 0027 yAxis->setSubTickPen(QPen(Qt::white, 1)); 0028 0029 xAxis->setTickLabelColor(Qt::white); 0030 yAxis->setTickLabelColor(Qt::white); 0031 0032 xAxis->setLabelColor(Qt::white); 0033 yAxis->setLabelColor(Qt::white); 0034 0035 xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 0036 yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 0037 xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 0038 yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 0039 xAxis->grid()->setZeroLinePen(Qt::NoPen); 0040 yAxis->grid()->setZeroLinePen(Qt::NoPen); 0041 0042 setInteractions(QCP::iRangeZoom); 0043 setInteraction(QCP::iRangeDrag, true); 0044 0045 QVector<QCPScatterStyle::ScatterShape> shapes; 0046 shapes << QCPScatterStyle::ssCross; 0047 shapes << QCPScatterStyle::ssPlus; 0048 shapes << QCPScatterStyle::ssCircle; 0049 shapes << QCPScatterStyle::ssSquare; 0050 shapes << QCPScatterStyle::ssDisc; 0051 shapes << QCPScatterStyle::ssDiamond; 0052 shapes << QCPScatterStyle::ssStar; 0053 shapes << QCPScatterStyle::ssTriangle; 0054 shapes << QCPScatterStyle::ssTriangleInverted; 0055 0056 this->setAutoAddPlottableToLegend(true); 0057 for (int i = 0; i < NUM_TILES; i++) 0058 { 0059 m_graph[i] = addGraph(); 0060 m_graph[i]->setLineStyle(QCPGraph::lsLine); 0061 m_graph[i]->setPen(QPen(QColor(TILE_COLOUR[i]), 2, Qt::SolidLine)); 0062 m_graph[i]->setScatterStyle(shapes[i]); 0063 m_graph[i]->setName(TILE_NAME[i]); 0064 0065 // Store the auto generated legends array for later manipulation 0066 m_legendItems[i] = this->legend->item(i); 0067 } 0068 0069 this->setAutoAddPlottableToLegend(false); 0070 for (int i = 0; i < NUM_TILES; i++) 0071 { 0072 // Add focus point graphs 0073 focusPoint[i] = addGraph(); 0074 focusPoint[i]->setLineStyle(QCPGraph::lsImpulse); 0075 focusPoint[i]->setPen(QPen(QColor(TILE_COLOUR[i]), 2, Qt::SolidLine)); 0076 focusPoint[i]->setScatterStyle(QCPScatterStyle(shapes[i], TILE_COLOUR[i], TILE_COLOUR[i], 10)); 0077 } 0078 0079 // determine font size 0080 if (parent != nullptr) 0081 setBasicFontSize(parent->font().pointSize()); 0082 else 0083 setBasicFontSize(DEFAULT_BASIC_FONT_SIZE); 0084 0085 connect(this, &QCustomPlot::mouseMove, [this](QMouseEvent * event) 0086 { 0087 double key = xAxis->pixelToCoord(event->localPos().x()); 0088 if (xAxis->range().contains(key)) 0089 { 0090 QCPGraph *graph = qobject_cast<QCPGraph *>(plottableAt(event->pos(), false)); 0091 0092 if (graph) 0093 { 0094 for (int i = 0; i < NUM_TILES; i++) 0095 { 0096 if (graph == focusPoint[i]) 0097 { 0098 if (focusPoint[i]->visible()) 0099 { 0100 int positionKey = focusPoint[i]->findBegin(key); 0101 double focusPosition = focusPoint[i]->dataMainKey(positionKey); 0102 double focusMeasure = focusPoint[i]->dataMainValue(positionKey); 0103 QToolTip::showText( 0104 event->globalPos(), 0105 i18nc("Graphics tooltip; %2 is tile code; %3 is tile name, %4 is Focus Position; %5 is Focus Measure;", 0106 "<style>table { background-color: white;}</style>" 0107 "<font color='%1'><table>" 0108 "<tr><td>Tile: </td><td>%2 (%3)</td></tr>" 0109 "<tr><td>Pos: </td><td>%4</td></tr>" 0110 "<tr><td>Val: </td><td>%5</td></tr>" 0111 "</table></font>", 0112 TILE_COLOUR[i], 0113 TILE_NAME[i], TILE_LONGNAME[i], 0114 QString::number(focusPosition, 'f', 0), 0115 QString::number(focusMeasure, 'g', 3))); 0116 } 0117 break; 0118 } 0119 } 0120 } 0121 } 0122 }); 0123 } 0124 0125 void AberrationInspectorPlot::init(QString yAxisLabel, double starUnits, bool useWeights, bool showLabels, bool showCFZ) 0126 { 0127 Q_UNUSED(useWeights); 0128 0129 yAxis->setLabel(yAxisLabel); 0130 m_starUnits = starUnits; 0131 m_showLabels = showLabels; 0132 m_showCFZ = showCFZ; 0133 for (int i = 0; i < NUM_TILES; i++) 0134 { 0135 m_graph[i]->data()->clear(); 0136 focusPoint[i]->data().clear(); 0137 focusPoint[i]->setData(QVector<double> {}, QVector<double> {}); 0138 } 0139 // Displat the legend 0140 this->legend->setVisible(true); 0141 } 0142 0143 void AberrationInspectorPlot::setAxes(const int tile) 0144 { 0145 if (tile == -1) 0146 { 0147 // Recalculate axes based on current setting of member variables 0148 const double xborder = (m_maxPosition - m_minPosition) / 10.0; 0149 xAxis->setRange(m_minPosition - xborder, m_maxPosition + xborder); 0150 0151 const double yborder = (m_maxMeasure - m_minMeasure) / 10.0; 0152 yAxis->setRange(m_minMeasure - yborder, m_maxMeasure + yborder); 0153 return; 0154 } 0155 // x-range - since its the same for each curve only do it once 0156 if (tile == 0) 0157 { 0158 if (m_positions.empty()) 0159 return; 0160 0161 m_minPosition = *std::min_element(m_positions.constBegin(), m_positions.constEnd()); 0162 m_maxPosition = *std::max_element(m_positions.constBegin(), m_positions.constEnd()); 0163 const double border = (m_maxPosition - m_minPosition) / 10.0; 0164 xAxis->setRange(m_minPosition - border, m_maxPosition + border); 0165 } 0166 0167 // y range 0168 if (m_measures[tile].empty()) 0169 return; 0170 0171 if (tile == 0) 0172 { 0173 m_minMeasure = *std::min_element(m_measures[tile].constBegin(), m_measures[tile].constEnd()); 0174 m_maxMeasure = *std::max_element(m_measures[tile].constBegin(), m_measures[tile].constEnd()); 0175 } 0176 else 0177 { 0178 m_minMeasure = std::min(m_minMeasure, *std::min_element(m_measures[tile].constBegin(), m_measures[tile].constEnd())); 0179 m_maxMeasure = std::max(m_maxMeasure, *std::max_element(m_measures[tile].constBegin(), m_measures[tile].constEnd())); 0180 } 0181 const double border = (m_maxMeasure - m_minMeasure) / 10.0; 0182 yAxis->setRange(m_minMeasure - border, m_maxMeasure + border); 0183 } 0184 0185 void AberrationInspectorPlot::addData(QVector<int> positions, QVector<double> measures, QVector<double> weights, 0186 QVector<bool> outliers) 0187 { 0188 Q_UNUSED(weights); 0189 Q_UNUSED(outliers); 0190 if (m_positions.count() == 0) 0191 m_positions.append(positions); 0192 0193 // Convert the incoming measures (e.g. pixels) to display measures (e.g. arc-secs) 0194 QVector<double> displayMeasures; 0195 for (int i = 0; i < measures.count(); i++) 0196 displayMeasures.push_back(getDisplayMeasure(measures[i])); 0197 m_measures.append(displayMeasures); 0198 0199 setAxes(m_measures.count() - 1); 0200 } 0201 0202 void AberrationInspectorPlot::drawMaxMin(int tile, double solutionPosition, double solutionMeasure) 0203 { 0204 // Do nothing for invalid positions 0205 if (solutionPosition <= 0) 0206 return; 0207 0208 double displayMeasure = getDisplayMeasure(solutionMeasure); 0209 m_minMeasure = std::min(m_minMeasure, displayMeasure); 0210 m_maxMeasure = std::max(m_maxMeasure, displayMeasure); 0211 0212 focusPoint[tile]->addData(solutionPosition, displayMeasure); 0213 m_labelItems[tile] = new QCPItemText(this); 0214 m_labelItems[tile]->setPositionAlignment(Qt::AlignVCenter | Qt::AlignHCenter); 0215 m_labelItems[tile]->setColor(TILE_COLOUR[tile]); 0216 m_labelItems[tile]->setBrush(Qt::white); 0217 m_labelItems[tile]->setPen(Qt::NoPen); 0218 m_labelItems[tile]->setFont(QFont(font().family(), (int) std::round(0.8 * basicFontSize()))); 0219 m_labelItems[tile]->position->setType(QCPItemPosition::ptPlotCoords); 0220 m_labelItems[tile]->setText(QString::number(solutionPosition, 'f', 0)); 0221 m_labelItems[tile]->position->setCoords(solutionPosition, displayMeasure * 0.8); 0222 m_labelItems[tile]->setVisible(m_showLabels); 0223 } 0224 0225 void AberrationInspectorPlot::drawCFZ(double solutionPosition, double solutionMeasure, int cfzSteps) 0226 { 0227 // Do nothing for invalid positions 0228 if (solutionPosition <= 0 || solutionMeasure <= 0) 0229 return; 0230 0231 if (!m_CFZ) 0232 m_CFZ = new QCPItemBracket(this); 0233 0234 m_CFZ->left->setType(QCPItemPosition::ptPlotCoords); 0235 m_CFZ->right->setType(QCPItemPosition::ptPlotCoords); 0236 0237 double y = m_minMeasure * 0.95; 0238 0239 m_CFZ->left->setCoords(solutionPosition + cfzSteps / 2.0, y); 0240 m_CFZ->right->setCoords(solutionPosition - cfzSteps / 2.0, y); 0241 m_CFZ->setLength(15); 0242 m_CFZ->setAntialiased(false); 0243 m_CFZ->setPen(QPen(QColor(Qt::yellow))); 0244 m_CFZ->setVisible(m_showCFZ); 0245 } 0246 0247 void AberrationInspectorPlot::setShowCFZ(bool setting) 0248 { 0249 m_showCFZ = setting; 0250 if (m_CFZ) 0251 m_CFZ->setVisible(setting); 0252 } 0253 0254 void AberrationInspectorPlot::setShowLabels(bool setting) 0255 { 0256 m_showLabels = setting; 0257 for (int tile = 0; tile < NUM_TILES; tile++) 0258 { 0259 if (m_labelItems[tile]) 0260 m_labelItems[tile]->setVisible(setting); 0261 } 0262 } 0263 0264 void AberrationInspectorPlot::drawCurve(int tile, Ekos::CurveFitting *curveFit, int maxmin, double measure, bool fit, 0265 double R2) 0266 { 0267 Q_UNUSED(fit); 0268 Q_UNUSED(R2); 0269 0270 if (curveFit == nullptr) 0271 return; 0272 0273 if (!fit) 0274 return; 0275 0276 // Extend max/mins if appropriate 0277 m_minPosition = std::min(m_minPosition, maxmin); 0278 m_maxPosition = std::max(m_maxPosition, maxmin); 0279 m_minMeasure = std::min(m_minMeasure, measure); 0280 m_maxMeasure = std::max(m_maxMeasure, measure); 0281 setAxes(-1); 0282 0283 if (m_graph[tile] != nullptr) 0284 { 0285 m_graph[tile]->data()->clear(); 0286 QCPRange range = xAxis->range(); 0287 double interval = range.size() / 40.0; 0288 0289 for(double x = range.lower; x < range.upper; x += interval) 0290 { 0291 double y = getDisplayMeasure(curveFit->f(x)); 0292 m_graph[tile]->addData(x, y); 0293 } 0294 } 0295 } 0296 0297 // Show only the graph elements relevant to the passed in useTile array 0298 void AberrationInspectorPlot::redrawCurve(bool useTile[NUM_TILES]) 0299 { 0300 for (int i = 0; i < NUM_TILES; i++) 0301 { 0302 // Show / hide the appropriate curves 0303 if (m_graph[i]) 0304 m_graph[i]->setVisible(useTile[i]); 0305 0306 // Only display legend entries for displayed graphs 0307 this->legend->item(i)->setVisible(useTile[i]); 0308 0309 // Show / hide the focus point and text labels appopriate to the selected curves 0310 if (focusPoint[i]) 0311 focusPoint[i]->setVisible(useTile[i]); 0312 if (m_labelItems[i]) 0313 m_labelItems[i]->setVisible(useTile[i] && m_showLabels); 0314 } 0315 } 0316 0317 void AberrationInspectorPlot::setBasicFontSize(int basicFontSize) 0318 { 0319 m_basicFontSize = basicFontSize; 0320 0321 // Axis Labels Settings 0322 yAxis->setLabelFont(QFont(font().family(), basicFontSize)); 0323 xAxis->setTickLabelFont(QFont(font().family(), (int) std::round(0.9 * basicFontSize))); 0324 yAxis->setTickLabelFont(QFont(font().family(), (int) std::round(0.9 * basicFontSize))); 0325 } 0326 0327 // Internally calculations are done in units of pixels for HFR and FWHM 0328 // If user preference is arcsecs then convert measures for display purposes. 0329 double AberrationInspectorPlot::getDisplayMeasure(const double measure) 0330 { 0331 return measure * m_starUnits; 0332 } 0333 0334 }