File indexing completed on 2024-05-12 15:28:09
0001 /*************************************************************************** 0002 File : XYInterpolationCurveDock.cpp 0003 Project : LabPlot 0004 -------------------------------------------------------------------- 0005 Copyright : (C) 2016 Stefan Gerlach (stefan.gerlach@uni.kn) 0006 Copyright : (C) 20016-2017 Alexander Semke (alexander.semke@web.de) 0007 Description : widget for editing properties of interpolation curves 0008 0009 ***************************************************************************/ 0010 0011 /*************************************************************************** 0012 * * 0013 * This program is free software; you can redistribute it and/or modify * 0014 * it under the terms of the GNU General Public License as published by * 0015 * the Free Software Foundation; either version 2 of the License, or * 0016 * (at your option) any later version. * 0017 * * 0018 * This program is distributed in the hope that it will be useful, * 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0021 * GNU General Public License for more details. * 0022 * * 0023 * You should have received a copy of the GNU General Public License * 0024 * along with this program; if not, write to the Free Software * 0025 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0026 * Boston, MA 02110-1301 USA * 0027 * * 0028 ***************************************************************************/ 0029 0030 #include "XYInterpolationCurveDock.h" 0031 #include "backend/core/AspectTreeModel.h" 0032 #include "backend/core/Project.h" 0033 #include "backend/worksheet/plots/cartesian/XYInterpolationCurve.h" 0034 #include "commonfrontend/widgets/TreeViewComboBox.h" 0035 0036 #include <QMenu> 0037 #include <QWidgetAction> 0038 #include <QStandardItemModel> 0039 0040 extern "C" { 0041 #include <gsl/gsl_interp.h> // gsl_interp types 0042 } 0043 #include <cmath> // isnan 0044 0045 /*! 0046 \class XYInterpolationCurveDock 0047 \brief Provides a widget for editing the properties of the XYInterpolationCurves 0048 (2D-curves defined by an interpolation) currently selected in 0049 the project explorer. 0050 0051 If more then one curves are set, the properties of the first column are shown. 0052 The changes of the properties are applied to all curves. 0053 The exclusions are the name, the comment and the datasets (columns) of 0054 the curves - these properties can only be changed if there is only one single curve. 0055 0056 \ingroup kdefrontend 0057 */ 0058 0059 XYInterpolationCurveDock::XYInterpolationCurveDock(QWidget* parent): XYCurveDock(parent) { 0060 } 0061 0062 /*! 0063 * // Tab "General" 0064 */ 0065 void XYInterpolationCurveDock::setupGeneral() { 0066 QWidget* generalTab = new QWidget(ui.tabGeneral); 0067 uiGeneralTab.setupUi(generalTab); 0068 m_leName = uiGeneralTab.leName; 0069 m_leComment = uiGeneralTab.leComment; 0070 0071 auto* gridLayout = static_cast<QGridLayout*>(generalTab->layout()); 0072 gridLayout->setContentsMargins(2,2,2,2); 0073 gridLayout->setHorizontalSpacing(2); 0074 gridLayout->setVerticalSpacing(2); 0075 0076 uiGeneralTab.cbDataSourceType->addItem(i18n("Spreadsheet")); 0077 uiGeneralTab.cbDataSourceType->addItem(i18n("XY-Curve")); 0078 0079 cbDataSourceCurve = new TreeViewComboBox(generalTab); 0080 gridLayout->addWidget(cbDataSourceCurve, 5, 2, 1, 2); 0081 cbXDataColumn = new TreeViewComboBox(generalTab); 0082 gridLayout->addWidget(cbXDataColumn, 6, 2, 1, 2); 0083 cbYDataColumn = new TreeViewComboBox(generalTab); 0084 gridLayout->addWidget(cbYDataColumn, 7, 2, 1, 2); 0085 0086 for (int i = 0; i < NSL_INTERP_TYPE_COUNT; i++) 0087 uiGeneralTab.cbType->addItem(i18n(nsl_interp_type_name[i])); 0088 #if GSL_MAJOR_VERSION < 2 0089 // disable Steffen spline item 0090 const QStandardItemModel* model = qobject_cast<const QStandardItemModel*>(uiGeneralTab.cbType->model()); 0091 QStandardItem* item = model->item(nsl_interp_type_steffen); 0092 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0093 #endif 0094 for (int i = 0; i < NSL_INTERP_PCH_VARIANT_COUNT; i++) 0095 uiGeneralTab.cbVariant->addItem(i18n(nsl_interp_pch_variant_name[i])); 0096 for (int i = 0; i < NSL_INTERP_EVALUATE_COUNT; i++) 0097 uiGeneralTab.cbEval->addItem(i18n(nsl_interp_evaluate_name[i])); 0098 0099 uiGeneralTab.cbPointsMode->addItem(i18n("Auto (5x data points)")); 0100 uiGeneralTab.cbPointsMode->addItem(i18n("Multiple of data points")); 0101 uiGeneralTab.cbPointsMode->addItem(i18n("Custom")); 0102 0103 //TODO: use line edits 0104 uiGeneralTab.sbMin->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); 0105 uiGeneralTab.sbMax->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); 0106 0107 uiGeneralTab.pbRecalculate->setIcon(QIcon::fromTheme("run-build")); 0108 0109 auto* layout = new QHBoxLayout(ui.tabGeneral); 0110 layout->setMargin(0); 0111 layout->addWidget(generalTab); 0112 0113 //Slots 0114 connect( uiGeneralTab.leName, &QLineEdit::textChanged, this, &XYInterpolationCurveDock::nameChanged ); 0115 connect( uiGeneralTab.leComment, &QLineEdit::textChanged, this, &XYInterpolationCurveDock::commentChanged ); 0116 connect(uiGeneralTab.chkVisible, &QCheckBox::clicked, this, &XYInterpolationCurveDock::visibilityChanged); 0117 connect(uiGeneralTab.cbDataSourceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYInterpolationCurveDock::dataSourceTypeChanged); 0118 connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYInterpolationCurveDock::autoRangeChanged); 0119 connect(uiGeneralTab.sbMin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYInterpolationCurveDock::xRangeMinChanged); 0120 connect(uiGeneralTab.sbMax, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYInterpolationCurveDock::xRangeMaxChanged); 0121 connect(uiGeneralTab.dateTimeEditMin, &QDateTimeEdit::dateTimeChanged, this, &XYInterpolationCurveDock::xRangeMinDateTimeChanged); 0122 connect(uiGeneralTab.dateTimeEditMax, &QDateTimeEdit::dateTimeChanged, this, &XYInterpolationCurveDock::xRangeMaxDateTimeChanged); 0123 connect(uiGeneralTab.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYInterpolationCurveDock::typeChanged); 0124 connect(uiGeneralTab.cbVariant, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYInterpolationCurveDock::variantChanged); 0125 //TODO: use line edits? 0126 connect(uiGeneralTab.sbTension, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYInterpolationCurveDock::tensionChanged); 0127 connect(uiGeneralTab.sbContinuity, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYInterpolationCurveDock::continuityChanged); 0128 connect(uiGeneralTab.sbBias, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYInterpolationCurveDock::biasChanged); 0129 connect(uiGeneralTab.cbEval, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYInterpolationCurveDock::evaluateChanged); 0130 // double? 0131 connect(uiGeneralTab.sbPoints, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYInterpolationCurveDock::numberOfPointsChanged); 0132 connect(uiGeneralTab.cbPointsMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYInterpolationCurveDock::pointsModeChanged); 0133 connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYInterpolationCurveDock::recalculateClicked); 0134 0135 connect(cbDataSourceCurve, &TreeViewComboBox::currentModelIndexChanged, this, &XYInterpolationCurveDock::dataSourceCurveChanged); 0136 connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYInterpolationCurveDock::xDataColumnChanged); 0137 connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYInterpolationCurveDock::yDataColumnChanged); 0138 } 0139 0140 void XYInterpolationCurveDock::initGeneralTab() { 0141 //if there are more then one curve in the list, disable the tab "general" 0142 if (m_curvesList.size() == 1) { 0143 uiGeneralTab.lName->setEnabled(true); 0144 uiGeneralTab.leName->setEnabled(true); 0145 uiGeneralTab.lComment->setEnabled(true); 0146 uiGeneralTab.leComment->setEnabled(true); 0147 0148 uiGeneralTab.leName->setText(m_curve->name()); 0149 uiGeneralTab.leComment->setText(m_curve->comment()); 0150 } else { 0151 uiGeneralTab.lName->setEnabled(false); 0152 uiGeneralTab.leName->setEnabled(false); 0153 uiGeneralTab.lComment->setEnabled(false); 0154 uiGeneralTab.leComment->setEnabled(false); 0155 0156 uiGeneralTab.leName->setText(QString()); 0157 uiGeneralTab.leComment->setText(QString()); 0158 } 0159 0160 //show the properties of the first curve 0161 m_interpolationCurve = dynamic_cast<XYInterpolationCurve*>(m_curve); 0162 checkColumnAvailability(cbXDataColumn, m_interpolationCurve->xDataColumn(), m_interpolationCurve->xDataColumnPath()); 0163 checkColumnAvailability(cbYDataColumn, m_interpolationCurve->yDataColumn(), m_interpolationCurve->yDataColumnPath()); 0164 0165 //data source 0166 uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(m_interpolationCurve->dataSourceType())); 0167 this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex()); 0168 XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, m_interpolationCurve->dataSourceCurve()); 0169 XYCurveDock::setModelIndexFromAspect(cbXDataColumn, m_interpolationCurve->xDataColumn()); 0170 XYCurveDock::setModelIndexFromAspect(cbYDataColumn, m_interpolationCurve->yDataColumn()); 0171 0172 //range widgets 0173 const auto* plot = static_cast<const CartesianPlot*>(m_interpolationCurve->parentAspect()); 0174 m_dateTimeRange = (plot->xRangeFormat() != CartesianPlot::RangeFormat::Numeric); 0175 if (!m_dateTimeRange) { 0176 uiGeneralTab.sbMin->setValue(m_interpolationData.xRange.first()); 0177 uiGeneralTab.sbMax->setValue(m_interpolationData.xRange.last()); 0178 } else { 0179 uiGeneralTab.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_interpolationData.xRange.first()) ); 0180 uiGeneralTab.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_interpolationData.xRange.last()) ); 0181 } 0182 0183 uiGeneralTab.lMin->setVisible(!m_dateTimeRange); 0184 uiGeneralTab.sbMin->setVisible(!m_dateTimeRange); 0185 uiGeneralTab.lMax->setVisible(!m_dateTimeRange); 0186 uiGeneralTab.sbMax->setVisible(!m_dateTimeRange); 0187 uiGeneralTab.lMinDateTime->setVisible(m_dateTimeRange); 0188 uiGeneralTab.dateTimeEditMin->setVisible(m_dateTimeRange); 0189 uiGeneralTab.lMaxDateTime->setVisible(m_dateTimeRange); 0190 uiGeneralTab.dateTimeEditMax->setVisible(m_dateTimeRange); 0191 0192 //auto range 0193 uiGeneralTab.cbAutoRange->setChecked(m_interpolationData.autoRange); 0194 this->autoRangeChanged(); 0195 0196 // update list of selectable types 0197 xDataColumnChanged(cbXDataColumn->currentModelIndex()); 0198 0199 uiGeneralTab.cbType->setCurrentIndex(m_interpolationData.type); 0200 this->typeChanged(m_interpolationData.type); 0201 uiGeneralTab.cbVariant->setCurrentIndex(m_interpolationData.variant); 0202 this->variantChanged(m_interpolationData.variant); 0203 uiGeneralTab.sbTension->setValue(m_interpolationData.tension); 0204 uiGeneralTab.sbContinuity->setValue(m_interpolationData.continuity); 0205 uiGeneralTab.sbBias->setValue(m_interpolationData.bias); 0206 uiGeneralTab.cbEval->setCurrentIndex(m_interpolationData.evaluate); 0207 0208 if (m_interpolationData.pointsMode == XYInterpolationCurve::PointsMode::Multiple) 0209 uiGeneralTab.sbPoints->setValue(m_interpolationData.npoints/5.); 0210 else 0211 uiGeneralTab.sbPoints->setValue(m_interpolationData.npoints); 0212 uiGeneralTab.cbPointsMode->setCurrentIndex(static_cast<int>(m_interpolationData.pointsMode)); 0213 0214 this->showInterpolationResult(); 0215 0216 uiGeneralTab.chkVisible->setChecked( m_curve->isVisible() ); 0217 0218 //Slots 0219 connect(m_interpolationCurve, &XYInterpolationCurve::aspectDescriptionChanged, this, &XYInterpolationCurveDock::curveDescriptionChanged); 0220 connect(m_interpolationCurve, &XYInterpolationCurve::dataSourceTypeChanged, this, &XYInterpolationCurveDock::curveDataSourceTypeChanged); 0221 connect(m_interpolationCurve, &XYInterpolationCurve::dataSourceCurveChanged, this, &XYInterpolationCurveDock::curveDataSourceCurveChanged); 0222 connect(m_interpolationCurve, &XYInterpolationCurve::xDataColumnChanged, this, &XYInterpolationCurveDock::curveXDataColumnChanged); 0223 connect(m_interpolationCurve, &XYInterpolationCurve::yDataColumnChanged, this, &XYInterpolationCurveDock::curveYDataColumnChanged); 0224 connect(m_interpolationCurve, &XYInterpolationCurve::interpolationDataChanged, this, &XYInterpolationCurveDock::curveInterpolationDataChanged); 0225 connect(m_interpolationCurve, &XYInterpolationCurve::sourceDataChanged, this, &XYInterpolationCurveDock::enableRecalculate); 0226 } 0227 0228 void XYInterpolationCurveDock::setModel() { 0229 QList<AspectType> list{AspectType::Folder, AspectType::Datapicker, AspectType::Worksheet, 0230 AspectType::CartesianPlot, AspectType::XYCurve, AspectType::XYAnalysisCurve}; 0231 cbDataSourceCurve->setTopLevelClasses(list); 0232 0233 QList<const AbstractAspect*> hiddenAspects; 0234 for (auto* curve : m_curvesList) 0235 hiddenAspects << curve; 0236 cbDataSourceCurve->setHiddenAspects(hiddenAspects); 0237 0238 list = {AspectType::Folder, AspectType::Workbook, AspectType::Datapicker, 0239 AspectType::DatapickerCurve, AspectType::Spreadsheet, AspectType::LiveDataSource, 0240 AspectType::Column, AspectType::Worksheet, AspectType::CartesianPlot, 0241 AspectType::XYFitCurve, AspectType::CantorWorksheet 0242 }; 0243 cbXDataColumn->setTopLevelClasses(list); 0244 cbYDataColumn->setTopLevelClasses(list); 0245 0246 cbDataSourceCurve->setModel(m_aspectTreeModel); 0247 cbXDataColumn->setModel(m_aspectTreeModel); 0248 cbYDataColumn->setModel(m_aspectTreeModel); 0249 0250 XYCurveDock::setModel(); 0251 } 0252 0253 /*! 0254 sets the curves. The properties of the curves in the list \c list can be edited in this widget. 0255 */ 0256 void XYInterpolationCurveDock::setCurves(QList<XYCurve*> list) { 0257 m_initializing = true; 0258 m_curvesList = list; 0259 m_curve = list.first(); 0260 m_aspect = m_curve; 0261 m_interpolationCurve = dynamic_cast<XYInterpolationCurve*>(m_curve); 0262 Q_ASSERT(m_interpolationCurve); 0263 m_aspectTreeModel = new AspectTreeModel(m_curve->project()); 0264 this->setModel(); 0265 m_interpolationData = m_interpolationCurve->interpolationData(); 0266 0267 SET_NUMBER_LOCALE 0268 uiGeneralTab.sbMin->setLocale(numberLocale); 0269 uiGeneralTab.sbMax->setLocale(numberLocale); 0270 uiGeneralTab.sbTension->setLocale(numberLocale); 0271 uiGeneralTab.sbContinuity->setLocale(numberLocale); 0272 uiGeneralTab.sbBias->setLocale(numberLocale); 0273 uiGeneralTab.sbPoints->setLocale(numberLocale); 0274 0275 initGeneralTab(); 0276 initTabs(); 0277 m_initializing = false; 0278 0279 //hide the "skip gaps" option after the curves were set 0280 ui.lLineSkipGaps->hide(); 0281 ui.chkLineSkipGaps->hide(); 0282 } 0283 0284 //************************************************************* 0285 //**** SLOTs for changes triggered in XYFitCurveDock ***** 0286 //************************************************************* 0287 void XYInterpolationCurveDock::dataSourceTypeChanged(int index) { 0288 const auto type = (XYAnalysisCurve::DataSourceType)index; 0289 if (type == XYAnalysisCurve::DataSourceType::Spreadsheet) { 0290 uiGeneralTab.lDataSourceCurve->hide(); 0291 cbDataSourceCurve->hide(); 0292 uiGeneralTab.lXColumn->show(); 0293 cbXDataColumn->show(); 0294 uiGeneralTab.lYColumn->show(); 0295 cbYDataColumn->show(); 0296 } else { 0297 uiGeneralTab.lDataSourceCurve->show(); 0298 cbDataSourceCurve->show(); 0299 uiGeneralTab.lXColumn->hide(); 0300 cbXDataColumn->hide(); 0301 uiGeneralTab.lYColumn->hide(); 0302 cbYDataColumn->hide(); 0303 } 0304 0305 if (m_initializing) 0306 return; 0307 0308 for (XYCurve* curve: m_curvesList) 0309 dynamic_cast<XYInterpolationCurve*>(curve)->setDataSourceType(type); 0310 } 0311 0312 void XYInterpolationCurveDock::dataSourceCurveChanged(const QModelIndex& index) { 0313 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0314 auto* dataSourceCurve = dynamic_cast<XYCurve*>(aspect); 0315 0316 // disable types that need more data points 0317 if (dataSourceCurve) 0318 this->updateSettings(dataSourceCurve->xColumn()); 0319 0320 if (m_initializing) 0321 return; 0322 0323 for (XYCurve* curve: m_curvesList) 0324 dynamic_cast<XYInterpolationCurve*>(curve)->setDataSourceCurve(dataSourceCurve); 0325 } 0326 0327 void XYInterpolationCurveDock::xDataColumnChanged(const QModelIndex& index) { 0328 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0329 AbstractColumn* column = nullptr; 0330 if (aspect) { 0331 column = dynamic_cast<AbstractColumn*>(aspect); 0332 Q_ASSERT(column); 0333 } 0334 0335 this->updateSettings(column); 0336 0337 if (m_initializing) 0338 return; 0339 0340 for (XYCurve* curve: m_curvesList) 0341 dynamic_cast<XYInterpolationCurve*>(curve)->setXDataColumn(column); 0342 0343 cbXDataColumn->useCurrentIndexText(true); 0344 cbXDataColumn->setInvalid(false); 0345 } 0346 0347 void XYInterpolationCurveDock::updateSettings(const AbstractColumn* column) { 0348 if (!column) 0349 return; 0350 0351 // disable types that need more data points 0352 if (uiGeneralTab.cbAutoRange->isChecked()) { 0353 uiGeneralTab.sbMin->setValue(column->minimum()); 0354 uiGeneralTab.sbMax->setValue(column->maximum()); 0355 } 0356 0357 unsigned int n = 0; 0358 for (int row = 0; row < column->rowCount(); row++) 0359 if (!std::isnan(column->valueAt(row)) && !column->isMasked(row)) 0360 n++; 0361 dataPoints = n; 0362 if (m_interpolationData.pointsMode == XYInterpolationCurve::PointsMode::Auto) 0363 pointsModeChanged(uiGeneralTab.cbPointsMode->currentIndex()); 0364 0365 const auto* model = qobject_cast<const QStandardItemModel*>(uiGeneralTab.cbType->model()); 0366 QStandardItem* item = model->item(nsl_interp_type_polynomial); 0367 if (dataPoints < gsl_interp_type_min_size(gsl_interp_polynomial) || dataPoints > 100) { // not good for many points 0368 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0369 if (uiGeneralTab.cbType->currentIndex() == nsl_interp_type_polynomial) 0370 uiGeneralTab.cbType->setCurrentIndex(0); 0371 } 0372 else 0373 item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); 0374 0375 item = model->item(nsl_interp_type_cspline); 0376 if (dataPoints < gsl_interp_type_min_size(gsl_interp_cspline)) { 0377 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0378 if (uiGeneralTab.cbType->currentIndex() == nsl_interp_type_cspline) 0379 uiGeneralTab.cbType->setCurrentIndex(0); 0380 } 0381 else 0382 item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); 0383 0384 item = model->item(nsl_interp_type_cspline_periodic); 0385 if (dataPoints < gsl_interp_type_min_size(gsl_interp_cspline_periodic)) { 0386 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0387 if (uiGeneralTab.cbType->currentIndex() == nsl_interp_type_cspline_periodic) 0388 uiGeneralTab.cbType->setCurrentIndex(0); 0389 } 0390 else 0391 item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); 0392 0393 item = model->item(nsl_interp_type_akima); 0394 if (dataPoints < gsl_interp_type_min_size(gsl_interp_akima)) { 0395 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0396 if (uiGeneralTab.cbType->currentIndex() == nsl_interp_type_akima) 0397 uiGeneralTab.cbType->setCurrentIndex(0); 0398 } 0399 else 0400 item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); 0401 0402 item = model->item(nsl_interp_type_akima_periodic); 0403 if (dataPoints < gsl_interp_type_min_size(gsl_interp_akima_periodic)) { 0404 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0405 if (uiGeneralTab.cbType->currentIndex() == nsl_interp_type_akima_periodic) 0406 uiGeneralTab.cbType->setCurrentIndex(0); 0407 } 0408 else 0409 item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); 0410 0411 #if GSL_MAJOR_VERSION >= 2 0412 item = model->item(nsl_interp_type_steffen); 0413 if (dataPoints < gsl_interp_type_min_size(gsl_interp_steffen)) { 0414 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 0415 if (uiGeneralTab.cbType->currentIndex() == nsl_interp_type_steffen) 0416 uiGeneralTab.cbType->setCurrentIndex(0); 0417 } 0418 else 0419 item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); 0420 #endif 0421 // own types work with 2 or more data points 0422 } 0423 0424 void XYInterpolationCurveDock::yDataColumnChanged(const QModelIndex& index) { 0425 if (m_initializing) 0426 return; 0427 0428 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0429 AbstractColumn* column = nullptr; 0430 if (aspect) { 0431 column = dynamic_cast<AbstractColumn*>(aspect); 0432 Q_ASSERT(column); 0433 } 0434 0435 for (XYCurve* curve: m_curvesList) 0436 dynamic_cast<XYInterpolationCurve*>(curve)->setYDataColumn(column); 0437 0438 cbYDataColumn->useCurrentIndexText(true); 0439 cbYDataColumn->setInvalid(false); 0440 } 0441 0442 void XYInterpolationCurveDock::autoRangeChanged() { 0443 bool autoRange = uiGeneralTab.cbAutoRange->isChecked(); 0444 m_interpolationData.autoRange = autoRange; 0445 0446 uiGeneralTab.lMin->setEnabled(!autoRange); 0447 uiGeneralTab.sbMin->setEnabled(!autoRange); 0448 uiGeneralTab.lMax->setEnabled(!autoRange); 0449 uiGeneralTab.sbMax->setEnabled(!autoRange); 0450 uiGeneralTab.lMinDateTime->setEnabled(!autoRange); 0451 uiGeneralTab.dateTimeEditMin->setEnabled(!autoRange); 0452 uiGeneralTab.lMaxDateTime->setEnabled(!autoRange); 0453 uiGeneralTab.dateTimeEditMax->setEnabled(!autoRange); 0454 0455 if (autoRange) { 0456 const AbstractColumn* xDataColumn = nullptr; 0457 if (m_interpolationCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) 0458 xDataColumn = m_interpolationCurve->xDataColumn(); 0459 else { 0460 if (m_interpolationCurve->dataSourceCurve()) 0461 xDataColumn = m_interpolationCurve->dataSourceCurve()->xColumn(); 0462 } 0463 0464 if (xDataColumn) { 0465 if (!m_dateTimeRange) { 0466 uiGeneralTab.sbMin->setValue(xDataColumn->minimum()); 0467 uiGeneralTab.sbMax->setValue(xDataColumn->maximum()); 0468 } else { 0469 uiGeneralTab.dateTimeEditMin->setDateTime(QDateTime::fromMSecsSinceEpoch(xDataColumn->minimum())); 0470 uiGeneralTab.dateTimeEditMax->setDateTime(QDateTime::fromMSecsSinceEpoch(xDataColumn->maximum())); 0471 } 0472 } 0473 } 0474 } 0475 0476 void XYInterpolationCurveDock::xRangeMinChanged(double value) { 0477 m_interpolationData.xRange.first() = value; 0478 uiGeneralTab.pbRecalculate->setEnabled(true); 0479 } 0480 0481 void XYInterpolationCurveDock::xRangeMaxChanged(double value) { 0482 m_interpolationData.xRange.last() = value; 0483 uiGeneralTab.pbRecalculate->setEnabled(true); 0484 } 0485 0486 void XYInterpolationCurveDock::xRangeMinDateTimeChanged(const QDateTime& dateTime) { 0487 if (m_initializing) 0488 return; 0489 0490 m_interpolationData.xRange.first() = dateTime.toMSecsSinceEpoch(); 0491 uiGeneralTab.pbRecalculate->setEnabled(true); 0492 } 0493 0494 void XYInterpolationCurveDock::xRangeMaxDateTimeChanged(const QDateTime& dateTime) { 0495 if (m_initializing) 0496 return; 0497 0498 m_interpolationData.xRange.last() = dateTime.toMSecsSinceEpoch(); 0499 uiGeneralTab.pbRecalculate->setEnabled(true); 0500 } 0501 0502 void XYInterpolationCurveDock::typeChanged(int index) { 0503 const auto type = (nsl_interp_type)index; 0504 m_interpolationData.type = type; 0505 0506 switch (type) { 0507 case nsl_interp_type_pch: 0508 uiGeneralTab.lVariant->show(); 0509 uiGeneralTab.cbVariant->show(); 0510 break; 0511 case nsl_interp_type_linear: 0512 case nsl_interp_type_polynomial: 0513 case nsl_interp_type_cspline: 0514 case nsl_interp_type_cspline_periodic: 0515 case nsl_interp_type_akima: 0516 case nsl_interp_type_akima_periodic: 0517 case nsl_interp_type_steffen: 0518 case nsl_interp_type_cosine: 0519 case nsl_interp_type_exponential: 0520 case nsl_interp_type_rational: 0521 uiGeneralTab.lVariant->hide(); 0522 uiGeneralTab.cbVariant->hide(); 0523 uiGeneralTab.cbVariant->setCurrentIndex(nsl_interp_pch_variant_finite_difference); 0524 uiGeneralTab.lParameter->hide(); 0525 uiGeneralTab.lTension->hide(); 0526 uiGeneralTab.sbTension->hide(); 0527 uiGeneralTab.lContinuity->hide(); 0528 uiGeneralTab.sbContinuity->hide(); 0529 uiGeneralTab.lBias->hide(); 0530 uiGeneralTab.sbBias->hide(); 0531 } 0532 0533 uiGeneralTab.pbRecalculate->setEnabled(true); 0534 } 0535 0536 void XYInterpolationCurveDock::variantChanged(int index) { 0537 const auto variant = (nsl_interp_pch_variant)index; 0538 m_interpolationData.variant = variant; 0539 0540 switch (variant) { 0541 case nsl_interp_pch_variant_finite_difference: 0542 uiGeneralTab.lParameter->hide(); 0543 uiGeneralTab.lTension->hide(); 0544 uiGeneralTab.sbTension->hide(); 0545 uiGeneralTab.lContinuity->hide(); 0546 uiGeneralTab.sbContinuity->hide(); 0547 uiGeneralTab.lBias->hide(); 0548 uiGeneralTab.sbBias->hide(); 0549 break; 0550 case nsl_interp_pch_variant_catmull_rom: 0551 uiGeneralTab.lParameter->show(); 0552 uiGeneralTab.lTension->show(); 0553 uiGeneralTab.sbTension->show(); 0554 uiGeneralTab.sbTension->setEnabled(false); 0555 uiGeneralTab.sbTension->setValue(0.0); 0556 uiGeneralTab.lContinuity->hide(); 0557 uiGeneralTab.sbContinuity->hide(); 0558 uiGeneralTab.lBias->hide(); 0559 uiGeneralTab.sbBias->hide(); 0560 break; 0561 case nsl_interp_pch_variant_cardinal: 0562 uiGeneralTab.lParameter->show(); 0563 uiGeneralTab.lTension->show(); 0564 uiGeneralTab.sbTension->show(); 0565 uiGeneralTab.sbTension->setEnabled(true); 0566 uiGeneralTab.lContinuity->hide(); 0567 uiGeneralTab.sbContinuity->hide(); 0568 uiGeneralTab.lBias->hide(); 0569 uiGeneralTab.sbBias->hide(); 0570 break; 0571 case nsl_interp_pch_variant_kochanek_bartels: 0572 uiGeneralTab.lParameter->show(); 0573 uiGeneralTab.lTension->show(); 0574 uiGeneralTab.sbTension->show(); 0575 uiGeneralTab.sbTension->setEnabled(true); 0576 uiGeneralTab.lContinuity->show(); 0577 uiGeneralTab.sbContinuity->show(); 0578 uiGeneralTab.lBias->show(); 0579 uiGeneralTab.sbBias->show(); 0580 break; 0581 } 0582 0583 uiGeneralTab.pbRecalculate->setEnabled(true); 0584 } 0585 0586 void XYInterpolationCurveDock::tensionChanged(double value) { 0587 m_interpolationData.tension = value; 0588 uiGeneralTab.pbRecalculate->setEnabled(true); 0589 } 0590 0591 void XYInterpolationCurveDock::continuityChanged(double value) { 0592 m_interpolationData.continuity = value; 0593 uiGeneralTab.pbRecalculate->setEnabled(true); 0594 } 0595 0596 void XYInterpolationCurveDock::biasChanged(double value) { 0597 m_interpolationData.bias = value; 0598 uiGeneralTab.pbRecalculate->setEnabled(true); 0599 } 0600 0601 void XYInterpolationCurveDock::evaluateChanged(int index) { 0602 m_interpolationData.evaluate = (nsl_interp_evaluate)index; 0603 uiGeneralTab.pbRecalculate->setEnabled(true); 0604 } 0605 0606 void XYInterpolationCurveDock::pointsModeChanged(int index) { 0607 const auto mode = (XYInterpolationCurve::PointsMode)index; 0608 0609 switch (mode) { 0610 case XYInterpolationCurve::PointsMode::Auto: 0611 uiGeneralTab.sbPoints->setEnabled(false); 0612 uiGeneralTab.sbPoints->setDecimals(0); 0613 uiGeneralTab.sbPoints->setSingleStep(1.0); 0614 uiGeneralTab.sbPoints->setValue(5*dataPoints); 0615 break; 0616 case XYInterpolationCurve::PointsMode::Multiple: 0617 uiGeneralTab.sbPoints->setEnabled(true); 0618 if (m_interpolationData.pointsMode != XYInterpolationCurve::PointsMode::Multiple && dataPoints > 0) { 0619 uiGeneralTab.sbPoints->setDecimals(2); 0620 uiGeneralTab.sbPoints->setValue(uiGeneralTab.sbPoints->value()/(double)dataPoints); 0621 uiGeneralTab.sbPoints->setSingleStep(0.01); 0622 } 0623 break; 0624 case XYInterpolationCurve::PointsMode::Custom: 0625 uiGeneralTab.sbPoints->setEnabled(true); 0626 if (m_interpolationData.pointsMode == XYInterpolationCurve::PointsMode::Multiple) { 0627 uiGeneralTab.sbPoints->setDecimals(0); 0628 uiGeneralTab.sbPoints->setSingleStep(1.0); 0629 uiGeneralTab.sbPoints->setValue(uiGeneralTab.sbPoints->value()*dataPoints); 0630 } 0631 break; 0632 } 0633 0634 m_interpolationData.pointsMode = mode; 0635 } 0636 0637 void XYInterpolationCurveDock::numberOfPointsChanged() { 0638 m_interpolationData.npoints = uiGeneralTab.sbPoints->value(); 0639 if (uiGeneralTab.cbPointsMode->currentIndex() == static_cast<int>(XYInterpolationCurve::PointsMode::Multiple)) 0640 m_interpolationData.npoints *= dataPoints; 0641 0642 // warn if points is smaller than data points 0643 QPalette palette = uiGeneralTab.sbPoints->palette(); 0644 if (m_interpolationData.npoints < dataPoints) 0645 palette.setColor(QPalette::Text, Qt::red); 0646 else 0647 palette.setColor(QPalette::Text, Qt::black); 0648 uiGeneralTab.sbPoints->setPalette(palette); 0649 0650 enableRecalculate(); 0651 } 0652 0653 void XYInterpolationCurveDock::recalculateClicked() { 0654 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0655 0656 for (XYCurve* curve: m_curvesList) 0657 dynamic_cast<XYInterpolationCurve*>(curve)->setInterpolationData(m_interpolationData); 0658 0659 uiGeneralTab.pbRecalculate->setEnabled(false); 0660 emit info(i18n("Interpolation status: %1", m_interpolationCurve->interpolationResult().status)); 0661 QApplication::restoreOverrideCursor(); 0662 } 0663 0664 void XYInterpolationCurveDock::enableRecalculate() const { 0665 if (m_initializing) 0666 return; 0667 0668 //no interpolation possible without the x- and y-data 0669 bool hasSourceData = false; 0670 if (m_interpolationCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) { 0671 AbstractAspect* aspectX = static_cast<AbstractAspect*>(cbXDataColumn->currentModelIndex().internalPointer()); 0672 AbstractAspect* aspectY = static_cast<AbstractAspect*>(cbYDataColumn->currentModelIndex().internalPointer()); 0673 hasSourceData = (aspectX != nullptr && aspectY != nullptr); 0674 if (aspectX) { 0675 cbXDataColumn->useCurrentIndexText(true); 0676 cbXDataColumn->setInvalid(false); 0677 } 0678 if (aspectY) { 0679 cbYDataColumn->useCurrentIndexText(true); 0680 cbYDataColumn->setInvalid(false); 0681 } 0682 } else { 0683 hasSourceData = (m_interpolationCurve->dataSourceCurve() != nullptr); 0684 } 0685 0686 uiGeneralTab.pbRecalculate->setEnabled(hasSourceData); 0687 } 0688 0689 /*! 0690 * show the result and details of the interpolation 0691 */ 0692 void XYInterpolationCurveDock::showInterpolationResult() { 0693 const auto& interpolationResult = m_interpolationCurve->interpolationResult(); 0694 if (!interpolationResult.available) { 0695 uiGeneralTab.teResult->clear(); 0696 return; 0697 } 0698 0699 QString str = i18n("status: %1", interpolationResult.status) + "<br>"; 0700 0701 if (!interpolationResult.valid) { 0702 uiGeneralTab.teResult->setText(str); 0703 return; //result is not valid, there was an error which is shown in the status-string, nothing to show more. 0704 } 0705 0706 SET_NUMBER_LOCALE 0707 if (interpolationResult.elapsedTime > 1000) 0708 str += i18n("calculation time: %1 s", numberLocale.toString(interpolationResult.elapsedTime/1000)) + "<br>"; 0709 else 0710 str += i18n("calculation time: %1 ms", numberLocale.toString(interpolationResult.elapsedTime)) + "<br>"; 0711 0712 str += "<br><br>"; 0713 0714 uiGeneralTab.teResult->setText(str); 0715 0716 //enable the "recalculate"-button if the source data was changed since the last interpolation 0717 uiGeneralTab.pbRecalculate->setEnabled(m_interpolationCurve->isSourceDataChangedSinceLastRecalc()); 0718 } 0719 0720 //************************************************************* 0721 //*********** SLOTs for changes triggered in XYCurve ********** 0722 //************************************************************* 0723 //General-Tab 0724 void XYInterpolationCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) { 0725 if (m_curve != aspect) 0726 return; 0727 0728 m_initializing = true; 0729 if (aspect->name() != uiGeneralTab.leName->text()) 0730 uiGeneralTab.leName->setText(aspect->name()); 0731 else if (aspect->comment() != uiGeneralTab.leComment->text()) 0732 uiGeneralTab.leComment->setText(aspect->comment()); 0733 m_initializing = false; 0734 } 0735 0736 void XYInterpolationCurveDock::curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType type) { 0737 m_initializing = true; 0738 uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(type)); 0739 m_initializing = false; 0740 } 0741 0742 void XYInterpolationCurveDock::curveDataSourceCurveChanged(const XYCurve* curve) { 0743 m_initializing = true; 0744 XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, curve); 0745 m_initializing = false; 0746 } 0747 0748 void XYInterpolationCurveDock::curveXDataColumnChanged(const AbstractColumn* column) { 0749 m_initializing = true; 0750 XYCurveDock::setModelIndexFromAspect(cbXDataColumn, column); 0751 m_initializing = false; 0752 } 0753 0754 void XYInterpolationCurveDock::curveYDataColumnChanged(const AbstractColumn* column) { 0755 m_initializing = true; 0756 XYCurveDock::setModelIndexFromAspect(cbYDataColumn, column); 0757 m_initializing = false; 0758 } 0759 0760 void XYInterpolationCurveDock::curveInterpolationDataChanged(const XYInterpolationCurve::InterpolationData& data) { 0761 m_initializing = true; 0762 m_interpolationData = data; 0763 uiGeneralTab.cbType->setCurrentIndex(m_interpolationData.type); 0764 this->typeChanged(m_interpolationData.type); 0765 0766 this->showInterpolationResult(); 0767 m_initializing = false; 0768 } 0769 0770 void XYInterpolationCurveDock::dataChanged() { 0771 this->enableRecalculate(); 0772 }