Warning, file /education/labplot/tests/cartesianplot/CartesianPlotTest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 File : CartesianPlotTest.cpp 0003 Project : LabPlot 0004 Description : Tests for cartesian plot 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2022 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "CartesianPlotTest.h" 0012 #include "tests/CommonTest.h" 0013 0014 #include "backend/core/Project.h" 0015 #include "backend/core/Workbook.h" 0016 #include "backend/lib/macros.h" 0017 #include "backend/matrix/Matrix.h" 0018 #include "backend/spreadsheet/Spreadsheet.h" 0019 #include "backend/worksheet/InfoElement.h" 0020 #include "backend/worksheet/plots/cartesian/CartesianCoordinateSystem.h" 0021 #include "backend/worksheet/plots/cartesian/CartesianPlot.h" 0022 #include "backend/worksheet/plots/cartesian/CartesianPlotPrivate.h" 0023 #include "backend/worksheet/plots/cartesian/Histogram.h" 0024 #include "backend/worksheet/plots/cartesian/XYCurve.h" 0025 #include "backend/worksheet/plots/cartesian/XYEquationCurve.h" 0026 #include "backend/worksheet/plots/cartesian/XYFitCurve.h" 0027 #include "commonfrontend/worksheet/WorksheetView.h" 0028 #include "kdefrontend/dockwidgets/XYFitCurveDock.h" 0029 0030 #include <QAction> 0031 #include <QUndoStack> 0032 0033 void CartesianPlotTest::initTestCase() { 0034 // // needed in order to have the signals triggered by SignallingUndoCommand, see LabPlot.cpp 0035 // //TODO: redesign/remove this 0036 qRegisterMetaType<const AbstractAspect*>("const AbstractAspect*"); 0037 qRegisterMetaType<const AbstractColumn*>("const AbstractColumn*"); 0038 } 0039 0040 // ############################################################################## 0041 // ##################### import of LabPlot projects ############################ 0042 // ############################################################################## 0043 0044 #define LOAD_PROJECT_DATA_CHANGE \ 0045 Project project; \ 0046 project.load(QFINDTESTDATA(QLatin1String("data/TestDataChange.lml"))); \ 0047 \ 0048 /* check the project tree for the imported project */ \ 0049 /* Spreadsheet */ \ 0050 auto* aspect = project.child<AbstractAspect>(0); \ 0051 QVERIFY(aspect != nullptr); \ 0052 if (aspect) \ 0053 QCOMPARE(aspect->name(), QLatin1String("Spreadsheet")); \ 0054 QVERIFY(aspect->type() == AspectType::Spreadsheet); \ 0055 auto s = dynamic_cast<Spreadsheet*>(aspect); \ 0056 if (!s) \ 0057 return; \ 0058 auto* c1 = static_cast<Column*>(s->child<Column>(0)); \ 0059 QVERIFY(c1 != nullptr); \ 0060 QCOMPARE(c1->name(), QLatin1String("1")); \ 0061 QVERIFY(c1->columnMode() == AbstractColumn::ColumnMode::Double); \ 0062 QVERIFY(c1->rowCount() == 100); \ 0063 QVERIFY(c1->valueAt(0) == 1.); \ 0064 QVERIFY(c1->valueAt(1) == 2.); \ 0065 auto* c2 = static_cast<Column*>(s->child<Column>(1)); \ 0066 QVERIFY(c2 != nullptr); \ 0067 QCOMPARE(c2->name(), QLatin1String("2")); \ 0068 QVERIFY(c2->columnMode() == AbstractColumn::ColumnMode::Double); \ 0069 QVERIFY(c2->rowCount() == 100); \ 0070 QVERIFY(c2->valueAt(0) == 1.); \ 0071 QVERIFY(c2->valueAt(1) == 2.); \ 0072 \ 0073 /* Worksheet */ \ 0074 aspect = project.child<AbstractAspect>(1); \ 0075 QVERIFY(aspect != nullptr); \ 0076 if (aspect) \ 0077 QCOMPARE(aspect->name(), QLatin1String("Worksheet - Spreadsheet")); \ 0078 QVERIFY(aspect->type() == AspectType::Worksheet); \ 0079 auto* w = dynamic_cast<Worksheet*>(aspect); \ 0080 if (!w) \ 0081 return; \ 0082 \ 0083 auto* plot = dynamic_cast<CartesianPlot*>(aspect->child<CartesianPlot>(0)); \ 0084 QVERIFY(plot != nullptr); \ 0085 if (!plot) \ 0086 return; \ 0087 \ 0088 /* curve */ \ 0089 auto* curve = dynamic_cast<XYCurve*>(plot->child<XYCurve>(0)); \ 0090 QVERIFY(curve != nullptr); \ 0091 if (!curve) \ 0092 return; \ 0093 QCOMPARE(curve->name(), QStringLiteral("2")); \ 0094 \ 0095 CHECK_RANGE(plot, curve, Dimension::X, 1., 2.); \ 0096 CHECK_RANGE(plot, curve, Dimension::Y, 1., 2.); \ 0097 \ 0098 auto* xAxis = static_cast<Axis*>(plot->child<Axis>(0)); \ 0099 QVERIFY(xAxis != nullptr); \ 0100 QCOMPARE(xAxis->orientation() == Axis::Orientation::Horizontal, true); \ 0101 \ 0102 auto* yAxis = static_cast<Axis*>(plot->child<Axis>(2)); \ 0103 QVERIFY(yAxis != nullptr); \ 0104 QCOMPARE(yAxis->orientation() == Axis::Orientation::Vertical, true); 0105 0106 #define LOAD_PROJECT_HISTOGRAM_FIT_CURVE \ 0107 Project project; \ 0108 project.load(QFINDTESTDATA(QLatin1String("data/histogram-fit-curve.lml"))); \ 0109 \ 0110 /* TODO: check the project tree for the imported project */ \ 0111 /* Spreadsheet */ \ 0112 auto* aspect = project.child<AbstractAspect>(0); \ 0113 QVERIFY(aspect != nullptr); \ 0114 if (aspect) \ 0115 QCOMPARE(aspect->name(), QLatin1String("Spreadsheet")); \ 0116 QVERIFY(aspect->type() == AspectType::Spreadsheet); \ 0117 auto s = dynamic_cast<Spreadsheet*>(aspect); \ 0118 if (!s) \ 0119 return; \ 0120 auto* c1 = static_cast<Column*>(s->child<Column>(0)); \ 0121 QVERIFY(c1 != nullptr); \ 0122 QCOMPARE(c1->name(), QLatin1String("Data")); \ 0123 QVERIFY(c1->columnMode() == AbstractColumn::ColumnMode::Double); \ 0124 QVERIFY(c1->rowCount() == 10000); \ 0125 \ 0126 /* Worksheet */ \ 0127 aspect = project.child<AbstractAspect>(1); \ 0128 QVERIFY(aspect != nullptr); \ 0129 if (aspect) \ 0130 QCOMPARE(aspect->name(), QLatin1String("Worksheet - Spreadsheet")); \ 0131 QVERIFY(aspect->type() == AspectType::Worksheet); \ 0132 auto* w = dynamic_cast<Worksheet*>(aspect); \ 0133 if (!w) \ 0134 return; \ 0135 \ 0136 auto* plot = dynamic_cast<CartesianPlot*>(aspect->child<CartesianPlot>(0)); \ 0137 QVERIFY(plot != nullptr); \ 0138 if (!plot) \ 0139 return; \ 0140 \ 0141 auto* h = dynamic_cast<Histogram*>(plot->child<Histogram>(0)); \ 0142 QVERIFY(h != nullptr); \ 0143 if (!h) \ 0144 return; \ 0145 QCOMPARE(h->name(), QStringLiteral("histogram")); \ 0146 \ 0147 /* curves */ \ 0148 auto* curve1 = dynamic_cast<XYCurve*>(plot->child<XYCurve>(0)); \ 0149 QVERIFY(curve1 != nullptr); \ 0150 if (!curve1) \ 0151 return; \ 0152 QCOMPARE(curve1->name(), QStringLiteral("fit")); \ 0153 auto* curve2 = dynamic_cast<XYCurve*>(plot->child<XYCurve>(1)); \ 0154 QVERIFY(curve2 != nullptr); \ 0155 if (!curve2) \ 0156 return; \ 0157 QCOMPARE(curve2->name(), QStringLiteral("f(x)")); \ 0158 \ 0159 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); \ 0160 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 1.); 0161 0162 #define SET_CARTESIAN_MOUSE_MODE(mode) \ 0163 QAction a(nullptr); \ 0164 a.setData(static_cast<int>(mode)); \ 0165 view->cartesianPlotMouseModeChanged(&a); 0166 0167 /*! 0168 * \brief CartesianPlotTest::changeData1: add data point 0169 * 0170 */ 0171 0172 void CartesianPlotTest::changeData1() { 0173 LOAD_PROJECT_DATA_CHANGE 0174 0175 // insert data 0176 c1->setValueAt(2, 3.); 0177 c2->setValueAt(2, 3.); 0178 0179 QVERIFY(c1->valueAt(2) == 3.); 0180 QVERIFY(c2->valueAt(2) == 3.); 0181 0182 CHECK_RANGE(plot, curve, Dimension::X, 1., 3.); 0183 CHECK_RANGE(plot, curve, Dimension::Y, 1., 3.); 0184 } 0185 0186 void CartesianPlotTest::changeData2() { 0187 LOAD_PROJECT_DATA_CHANGE 0188 0189 // insert data 0190 c1->setValueAt(2, 3.); 0191 c2->setValueAt(2, 2.); 0192 0193 QVERIFY(c1->valueAt(2) == 3.); 0194 QVERIFY(c2->valueAt(2) == 2.); 0195 0196 CHECK_RANGE(plot, curve, Dimension::X, 1., 3.); 0197 CHECK_RANGE(plot, curve, Dimension::Y, 1., 2.); 0198 0199 DEBUG_RANGE(plot, curve); 0200 } 0201 0202 void CartesianPlotTest::changeData3() { 0203 LOAD_PROJECT_DATA_CHANGE 0204 0205 // insert data 0206 c1->setValueAt(2, 2.); 0207 c2->setValueAt(2, 3.); 0208 0209 QVERIFY(c1->valueAt(2) == 2.); 0210 QVERIFY(c2->valueAt(2) == 3.); 0211 0212 CHECK_RANGE(plot, curve, Dimension::X, 1., 2.); 0213 CHECK_RANGE(plot, curve, Dimension::Y, 1., 3.); 0214 } 0215 0216 void CartesianPlotTest::changeData4() { 0217 LOAD_PROJECT_DATA_CHANGE 0218 0219 // insert data 0220 c2->setValueAt(2, 3.); 0221 c1->setValueAt(2, 3.); 0222 0223 QVERIFY(c1->valueAt(2) == 3.); 0224 QVERIFY(c2->valueAt(2) == 3.); 0225 0226 CHECK_RANGE(plot, curve, Dimension::X, 1., 3.); 0227 CHECK_RANGE(plot, curve, Dimension::Y, 1., 3.); 0228 } 0229 0230 void CartesianPlotTest::changeData5() { 0231 LOAD_PROJECT_DATA_CHANGE 0232 0233 // insert data 0234 c2->setValueAt(2, 2.); 0235 c1->setValueAt(2, 3.); 0236 0237 QVERIFY(c1->valueAt(2) == 3.); 0238 QVERIFY(c2->valueAt(2) == 2.); 0239 0240 CHECK_RANGE(plot, curve, Dimension::X, 1., 3.); 0241 CHECK_RANGE(plot, curve, Dimension::Y, 1., 2.); 0242 } 0243 0244 void CartesianPlotTest::changeData6() { 0245 LOAD_PROJECT_DATA_CHANGE 0246 0247 // insert data 0248 c2->setValueAt(2, 3.); 0249 c1->setValueAt(2, 2.); 0250 0251 QVERIFY(c1->valueAt(2) == 2.); 0252 QVERIFY(c2->valueAt(2) == 3.); 0253 0254 CHECK_RANGE(plot, curve, Dimension::X, 1., 2.); 0255 CHECK_RANGE(plot, curve, Dimension::Y, 1., 3.); 0256 } 0257 0258 // check deleting curve 0259 0260 void CartesianPlotTest::deleteCurveAutoscale() { 0261 LOAD_PROJECT_HISTOGRAM_FIT_CURVE 0262 0263 // delete curve in plot 0264 plot->removeChild(curve2); 0265 0266 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); 0267 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 0.45); 0268 } 0269 0270 void CartesianPlotTest::deleteCurveNoAutoscale() { 0271 LOAD_PROJECT_HISTOGRAM_FIT_CURVE 0272 const auto cs = plot->coordinateSystem(curve2->coordinateSystemIndex()); 0273 plot->enableAutoScale(Dimension::Y, cs->index(Dimension::Y), false, false); 0274 0275 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); 0276 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 1.); 0277 0278 // delete curve in plot 0279 plot->removeChild(curve2); 0280 0281 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); 0282 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 1.); 0283 0284 QCOMPARE(plot->autoScale(Dimension::Y, cs->index(Dimension::Y)), false); 0285 } 0286 0287 void CartesianPlotTest::invisibleCurveAutoscale() { 0288 LOAD_PROJECT_HISTOGRAM_FIT_CURVE 0289 0290 curve2->setVisible(false); 0291 0292 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); 0293 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 0.45); 0294 } 0295 0296 void CartesianPlotTest::invisibleCurveNoAutoscale() { 0297 LOAD_PROJECT_HISTOGRAM_FIT_CURVE 0298 const auto cs = plot->coordinateSystem(curve2->coordinateSystemIndex()); 0299 plot->enableAutoScale(Dimension::Y, cs->index(Dimension::Y), false, false); 0300 0301 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); 0302 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 1.); 0303 0304 curve2->setVisible(false); 0305 0306 CHECK_RANGE(plot, curve1, Dimension::X, -4., 4.); 0307 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 1.); 0308 0309 QCOMPARE(plot->autoScale(Dimension::Y, cs->index(Dimension::Y)), false); 0310 } 0311 0312 void CartesianPlotTest::equationCurveEquationChangedAutoScale() { 0313 LOAD_PROJECT_HISTOGRAM_FIT_CURVE 0314 const auto cs = plot->coordinateSystem(curve2->coordinateSystemIndex()); 0315 0316 QCOMPARE(curve2->type(), AspectType::XYEquationCurve); 0317 auto eqc = static_cast<XYEquationCurve*>(curve2); 0318 0319 auto equationData = eqc->equationData(); 0320 equationData.max = QStringLiteral("10"); 0321 eqc->setEquationData(equationData); 0322 0323 CHECK_RANGE(plot, curve2, Dimension::X, -4., 10.); 0324 CHECK_RANGE(plot, curve2, Dimension::Y, 0., 10.); 0325 0326 QCOMPARE(plot->autoScale(Dimension::Y, cs->index(Dimension::Y)), true); 0327 } 0328 0329 void CartesianPlotTest::equationCurveEquationChangedNoAutoScale() { 0330 LOAD_PROJECT_HISTOGRAM_FIT_CURVE 0331 const auto cs = plot->coordinateSystem(curve2->coordinateSystemIndex()); 0332 plot->enableAutoScale(Dimension::Y, cs->index(Dimension::Y), false, false); 0333 0334 QCOMPARE(curve2->type(), AspectType::XYEquationCurve); 0335 auto eqc = static_cast<XYEquationCurve*>(curve2); 0336 0337 auto equationData = eqc->equationData(); 0338 equationData.max = QStringLiteral("10"); 0339 eqc->setEquationData(equationData); 0340 0341 CHECK_RANGE(plot, curve2, Dimension::X, -4., 10.); 0342 CHECK_RANGE(plot, curve2, Dimension::Y, 0., 1.); 0343 0344 QCOMPARE(plot->autoScale(Dimension::Y, cs->index(Dimension::Y)), false); 0345 } 0346 0347 void CartesianPlotTest::undoInfoElement() { 0348 auto* project = new Project(); 0349 auto* worksheet = new Worksheet(QStringLiteral("ws")); 0350 project->addChild(worksheet); 0351 0352 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0353 worksheet->addChild(plot); 0354 0355 auto* curve = new XYCurve(QStringLiteral("curve")); 0356 plot->addChild(curve); 0357 0358 auto* info = new InfoElement(QStringLiteral("info"), plot, curve, 0.); 0359 plot->addChild(info); 0360 0361 QCOMPARE(plot->childCount<InfoElement>(), 1); 0362 0363 // undo the last step 0364 project->undoStack()->undo(); 0365 QCOMPARE(plot->childCount<InfoElement>(), 0); 0366 0367 // redo 0368 project->undoStack()->redo(); 0369 QCOMPARE(plot->childCount<InfoElement>(), 1); 0370 } 0371 0372 void CartesianPlotTest::axisFormat() { 0373 // testing #74 0374 0375 QString savePath; 0376 { 0377 Project project; 0378 0379 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0380 project.addChild(sheet); 0381 0382 sheet->setColumnCount(2); 0383 sheet->setRowCount(3); 0384 0385 sheet->column(0)->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0386 sheet->column(1)->setColumnMode(AbstractColumn::ColumnMode::Integer); 0387 0388 sheet->column(0)->setDateTimeAt(0, QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0389 sheet->column(0)->setDateTimeAt(1, QDateTime::fromString(QStringLiteral("2022-02-04 12:23:00"), Qt::ISODate)); 0390 sheet->column(0)->setDateTimeAt(2, QDateTime::fromString(QStringLiteral("2022-02-05 12:23:00"), Qt::ISODate)); 0391 0392 QCOMPARE(sheet->column(0)->dateTimeAt(0), QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0393 0394 sheet->column(1)->setValueAt(0, 0); 0395 sheet->column(1)->setValueAt(1, 1); 0396 sheet->column(1)->setValueAt(2, 2); 0397 0398 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0399 project.addChild(worksheet); 0400 0401 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0402 worksheet->addChild(plot); 0403 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0404 0405 auto* curve = new XYCurve(QStringLiteral("curve")); 0406 plot->addChild(curve); 0407 0408 curve->setXColumn(sheet->column(0)); 0409 curve->setYColumn(sheet->column(1)); 0410 0411 auto* xAxis = static_cast<Axis*>(plot->child<Axis>(0)); 0412 QVERIFY(xAxis); 0413 QCOMPARE(xAxis->name(), QStringLiteral("x")); 0414 0415 const auto original = xAxis->labelsDateTimeFormat(); 0416 const auto newFormat = QStringLiteral("yyyy-MM-dd hh:mm"); 0417 QVERIFY(original != newFormat); 0418 xAxis->setLabelsDateTimeFormat(newFormat); 0419 0420 SAVE_PROJECT("TestAxisDateTimeFormat.lml"); 0421 } 0422 0423 { 0424 Project project; 0425 project.load(savePath); 0426 0427 /* check the project tree for the imported project */ 0428 /* Spreadsheet */ 0429 auto* aspect = project.child<AbstractAspect>(0); 0430 QVERIFY(aspect); 0431 QCOMPARE(aspect->name(), QLatin1String("Spreadsheet")); 0432 QVERIFY(aspect->type() == AspectType::Spreadsheet); 0433 0434 /* Worksheet */ 0435 aspect = project.child<AbstractAspect>(1); 0436 QVERIFY(aspect); 0437 QCOMPARE(aspect->name(), QLatin1String("Worksheet")); 0438 QVERIFY(aspect->type() == AspectType::Worksheet); 0439 auto* w = dynamic_cast<Worksheet*>(aspect); 0440 QVERIFY(w); 0441 0442 auto* plot = dynamic_cast<CartesianPlot*>(aspect->child<CartesianPlot>(0)); 0443 QVERIFY(plot); 0444 0445 auto* xAxis = static_cast<Axis*>(plot->child<Axis>(0)); 0446 QVERIFY(xAxis); 0447 QCOMPARE(xAxis->name(), QStringLiteral("x")); 0448 QCOMPARE(xAxis->labelsDateTimeFormat(), QStringLiteral("yyyy-MM-dd hh:mm")); 0449 } 0450 } 0451 0452 void CartesianPlotTest::shiftLeftAutoScale() { 0453 Project project; 0454 auto* ws = new Worksheet(QStringLiteral("worksheet")); 0455 QVERIFY(ws != nullptr); 0456 project.addChild(ws); 0457 0458 auto* p = new CartesianPlot(QStringLiteral("plot")); 0459 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0460 QVERIFY(p != nullptr); 0461 ws->addChild(p); 0462 0463 auto* curve{new XYEquationCurve(QStringLiteral("f(x)"))}; 0464 curve->setCoordinateSystemIndex(p->defaultCoordinateSystemIndex()); 0465 p->addChild(curve); 0466 0467 XYEquationCurve::EquationData data; 0468 data.min = QStringLiteral("1"); 0469 data.max = QStringLiteral("2"); 0470 data.count = 1000; 0471 data.expression1 = QStringLiteral("x"); 0472 curve->setEquationData(data); 0473 curve->recalculate(); 0474 0475 CHECK_RANGE(p, curve, Dimension::X, 1., 2.); 0476 CHECK_RANGE(p, curve, Dimension::Y, 1., 2.); 0477 0478 p->shiftLeftX(); 0479 0480 // Autoscale of the y range was done 0481 CHECK_RANGE(p, curve, Dimension::X, 1.1, 2.1); 0482 CHECK_RANGE(p, curve, Dimension::Y, 1.1, 2.); // changed range 0483 } 0484 0485 void CartesianPlotTest::shiftRightAutoScale() { 0486 Project project; 0487 auto* ws = new Worksheet(QStringLiteral("worksheet")); 0488 QVERIFY(ws != nullptr); 0489 project.addChild(ws); 0490 0491 auto* p = new CartesianPlot(QStringLiteral("plot")); 0492 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0493 QVERIFY(p != nullptr); 0494 ws->addChild(p); 0495 0496 auto* curve{new XYEquationCurve(QStringLiteral("f(x)"))}; 0497 curve->setCoordinateSystemIndex(p->defaultCoordinateSystemIndex()); 0498 p->addChild(curve); 0499 0500 XYEquationCurve::EquationData data; 0501 data.min = QStringLiteral("1"); 0502 data.max = QStringLiteral("2"); 0503 data.count = 1000; 0504 data.expression1 = QStringLiteral("x"); 0505 curve->setEquationData(data); 0506 curve->recalculate(); 0507 0508 CHECK_RANGE(p, curve, Dimension::X, 1., 2.); 0509 CHECK_RANGE(p, curve, Dimension::Y, 1., 2.); 0510 0511 p->shiftRightX(); 0512 0513 // Autoscale of the y range was done 0514 CHECK_RANGE(p, curve, Dimension::X, 0.9, 1.9); 0515 CHECK_RANGE(p, curve, Dimension::Y, 1., 1.9); // changed range 0516 } 0517 0518 void CartesianPlotTest::shiftUpAutoScale() { 0519 Project project; 0520 auto* ws = new Worksheet(QStringLiteral("worksheet")); 0521 QVERIFY(ws != nullptr); 0522 project.addChild(ws); 0523 0524 auto* p = new CartesianPlot(QStringLiteral("plot")); 0525 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0526 QVERIFY(p != nullptr); 0527 ws->addChild(p); 0528 0529 auto* curve{new XYEquationCurve(QStringLiteral("f(x)"))}; 0530 curve->setCoordinateSystemIndex(p->defaultCoordinateSystemIndex()); 0531 p->addChild(curve); 0532 0533 XYEquationCurve::EquationData data; 0534 data.min = QStringLiteral("1"); 0535 data.max = QStringLiteral("2"); 0536 data.count = 1000; 0537 data.expression1 = QStringLiteral("x"); 0538 curve->setEquationData(data); 0539 curve->recalculate(); 0540 0541 CHECK_RANGE(p, curve, Dimension::X, 1., 2.); 0542 CHECK_RANGE(p, curve, Dimension::Y, 1., 2.); 0543 0544 p->shiftUpY(); 0545 0546 // Autoscale of the y range was done 0547 CHECK_RANGE(p, curve, Dimension::X, 1., 1.9); 0548 CHECK_RANGE(p, curve, Dimension::Y, 0.9, 1.9); // changed range 0549 } 0550 0551 void CartesianPlotTest::shiftDownAutoScale() { 0552 Project project; 0553 auto* ws = new Worksheet(QStringLiteral("worksheet")); 0554 QVERIFY(ws != nullptr); 0555 project.addChild(ws); 0556 0557 auto* p = new CartesianPlot(QStringLiteral("plot")); 0558 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0559 QVERIFY(p != nullptr); 0560 ws->addChild(p); 0561 0562 auto* curve{new XYEquationCurve(QStringLiteral("f(x)"))}; 0563 curve->setCoordinateSystemIndex(p->defaultCoordinateSystemIndex()); 0564 p->addChild(curve); 0565 0566 XYEquationCurve::EquationData data; 0567 data.min = QStringLiteral("1"); 0568 data.max = QStringLiteral("2"); 0569 data.count = 1000; 0570 data.expression1 = QStringLiteral("x"); 0571 curve->setEquationData(data); 0572 curve->recalculate(); 0573 0574 CHECK_RANGE(p, curve, Dimension::X, 1., 2.); 0575 CHECK_RANGE(p, curve, Dimension::Y, 1., 2.); 0576 0577 p->shiftDownY(); 0578 0579 // Autoscale of the y range was done 0580 CHECK_RANGE(p, curve, Dimension::X, 1.1, 2.); 0581 CHECK_RANGE(p, curve, Dimension::Y, 1.1, 2.1); // changed range 0582 } 0583 0584 void CartesianPlotTest::rangeFormatYDataChanged() { 0585 Project project; 0586 0587 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0588 project.addChild(sheet); 0589 0590 sheet->setColumnCount(2); 0591 sheet->setRowCount(3); 0592 0593 sheet->column(0)->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0594 sheet->column(1)->setColumnMode(AbstractColumn::ColumnMode::Integer); 0595 0596 sheet->column(0)->setDateTimeAt(0, QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0597 sheet->column(0)->setDateTimeAt(1, QDateTime::fromString(QStringLiteral("2022-02-04 12:23:00"), Qt::ISODate)); 0598 sheet->column(0)->setDateTimeAt(2, QDateTime::fromString(QStringLiteral("2022-02-05 12:23:00"), Qt::ISODate)); 0599 0600 QCOMPARE(sheet->column(0)->dateTimeAt(0), QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0601 0602 sheet->column(1)->setValueAt(0, 0); 0603 sheet->column(1)->setValueAt(1, 1); 0604 sheet->column(1)->setValueAt(2, 2); 0605 0606 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0607 project.addChild(worksheet); 0608 0609 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0610 worksheet->addChild(plot); 0611 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0612 0613 auto* curve = new XYCurve(QStringLiteral("curve")); 0614 plot->addChild(curve); 0615 0616 curve->setXColumn(sheet->column(0)); 0617 curve->setYColumn(sheet->column(1)); 0618 0619 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::DateTime); 0620 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0621 0622 // simulate data change 0623 plot->dataChanged(curve, Dimension::Y); 0624 0625 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::DateTime); 0626 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0627 } 0628 0629 void CartesianPlotTest::rangeFormatXDataChanged() { 0630 Project project; 0631 0632 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0633 project.addChild(sheet); 0634 0635 sheet->setColumnCount(2); 0636 sheet->setRowCount(3); 0637 0638 sheet->column(0)->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0639 sheet->column(1)->setColumnMode(AbstractColumn::ColumnMode::Integer); 0640 0641 sheet->column(0)->setDateTimeAt(0, QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0642 sheet->column(0)->setDateTimeAt(1, QDateTime::fromString(QStringLiteral("2022-02-04 12:23:00"), Qt::ISODate)); 0643 sheet->column(0)->setDateTimeAt(2, QDateTime::fromString(QStringLiteral("2022-02-05 12:23:00"), Qt::ISODate)); 0644 0645 QCOMPARE(sheet->column(0)->dateTimeAt(0), QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0646 0647 sheet->column(1)->setValueAt(0, 0); 0648 sheet->column(1)->setValueAt(1, 1); 0649 sheet->column(1)->setValueAt(2, 2); 0650 0651 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0652 project.addChild(worksheet); 0653 0654 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0655 worksheet->addChild(plot); 0656 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0657 0658 auto* curve = new XYCurve(QStringLiteral("curve")); 0659 plot->addChild(curve); 0660 0661 curve->setXColumn(sheet->column(1)); 0662 curve->setYColumn(sheet->column(0)); 0663 0664 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0665 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::DateTime); 0666 0667 // simulate data change 0668 plot->dataChanged(curve, Dimension::X); 0669 0670 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0671 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::DateTime); 0672 } 0673 0674 void CartesianPlotTest::rangeFormatNonDefaultRange() { 0675 Project project; 0676 0677 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0678 project.addChild(sheet); 0679 0680 sheet->setColumnCount(4); 0681 sheet->setRowCount(3); 0682 0683 sheet->column(0)->setColumnMode(AbstractColumn::ColumnMode::Integer); 0684 sheet->column(1)->setColumnMode(AbstractColumn::ColumnMode::Integer); 0685 sheet->column(2)->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0686 sheet->column(3)->setColumnMode(AbstractColumn::ColumnMode::Integer); 0687 0688 sheet->column(0)->setValueAt(0, 0); 0689 sheet->column(0)->setValueAt(1, 1); 0690 sheet->column(0)->setValueAt(2, 2); 0691 0692 sheet->column(1)->setValueAt(0, 5); 0693 sheet->column(1)->setValueAt(1, 6); 0694 sheet->column(1)->setValueAt(2, 7); 0695 0696 sheet->column(2)->setDateTimeAt(0, QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0697 sheet->column(2)->setDateTimeAt(1, QDateTime::fromString(QStringLiteral("2022-02-04 12:23:00"), Qt::ISODate)); 0698 sheet->column(2)->setDateTimeAt(2, QDateTime::fromString(QStringLiteral("2022-02-05 12:23:00"), Qt::ISODate)); 0699 0700 QCOMPARE(sheet->column(2)->dateTimeAt(0), QDateTime::fromString(QStringLiteral("2022-02-03 12:23:00"), Qt::ISODate)); 0701 0702 sheet->column(3)->setValueAt(0, 8); 0703 sheet->column(3)->setValueAt(1, 10); 0704 sheet->column(3)->setValueAt(2, 9); 0705 0706 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0707 project.addChild(worksheet); 0708 0709 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0710 worksheet->addChild(plot); 0711 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0712 0713 // Create new cSystem 0714 Range<double> xRange; 0715 xRange.setFormat(RangeT::Format::Numeric); 0716 Range<double> yRange; 0717 yRange.setFormat(RangeT::Format::Numeric); 0718 plot->addXRange(xRange); 0719 plot->addYRange(yRange); 0720 CartesianCoordinateSystem* cSystem = new CartesianCoordinateSystem(plot); 0721 cSystem->setIndex(Dimension::X, 1); 0722 cSystem->setIndex(Dimension::Y, 1); 0723 plot->addCoordinateSystem(cSystem); 0724 0725 auto* curve2 = new XYCurve(QStringLiteral("curve2")); 0726 plot->addChild(curve2); 0727 0728 curve2->setCoordinateSystemIndex(1); 0729 0730 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0731 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0732 QCOMPARE(plot->rangeFormat(Dimension::X, 1), RangeT::Format::Numeric); 0733 QCOMPARE(plot->rangeFormat(Dimension::Y, 1), RangeT::Format::Numeric); 0734 0735 curve2->setXColumn(sheet->column(2)); 0736 0737 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0738 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0739 QCOMPARE(plot->rangeFormat(Dimension::X, 1), RangeT::Format::DateTime); 0740 QCOMPARE(plot->rangeFormat(Dimension::Y, 1), RangeT::Format::Numeric); 0741 0742 curve2->setYColumn(sheet->column(3)); 0743 0744 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0745 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0746 QCOMPARE(plot->rangeFormat(Dimension::X, 1), RangeT::Format::DateTime); 0747 QCOMPARE(plot->rangeFormat(Dimension::Y, 1), RangeT::Format::Numeric); 0748 0749 plot->dataChanged(curve2, Dimension::X); 0750 0751 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0752 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0753 QCOMPARE(plot->rangeFormat(Dimension::X, 1), RangeT::Format::DateTime); 0754 QCOMPARE(plot->rangeFormat(Dimension::Y, 1), RangeT::Format::Numeric); 0755 } 0756 0757 /*! 0758 * \brief CartesianPlotTest::invalidcSystem 0759 * Plot with 2 CoordinateSystems (with common x range), but the second has invalid start end (0, 0). 0760 * This scenario shall not destroy the x range when zooming in 0761 * 0762 */ 0763 void CartesianPlotTest::invalidcSystem() { 0764 Project project; 0765 0766 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0767 project.addChild(worksheet); 0768 auto* view = dynamic_cast<WorksheetView*>(worksheet->view()); 0769 QVERIFY(view != nullptr); 0770 view->initActions(); // needed by SET_CARTESIAN_MOUSE_MODE() 0771 0772 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0773 worksheet->addChild(plot); 0774 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0775 SET_CARTESIAN_MOUSE_MODE(CartesianPlot::MouseMode::ZoomXSelection) // must be set after the plot was added 0776 0777 // Create new cSystem 0778 Range<double> yRange; 0779 yRange.setFormat(RangeT::Format::Numeric); 0780 plot->addYRange(yRange); 0781 plot->addCoordinateSystem(); 0782 QCOMPARE(plot->coordinateSystemCount(), 2); 0783 0784 auto* cSystem{plot->coordinateSystem(1)}; 0785 cSystem->setIndex(Dimension::Y, 1); 0786 plot->setRangeDirty(Dimension::Y, 1, true); 0787 plot->retransformScale(Dimension::Y, 1); 0788 0789 { 0790 CHECK_RANGE_CSYSTEMINDEX(plot, 0, Dimension::X, 0., 1.); 0791 CHECK_RANGE_CSYSTEMINDEX(plot, 0, Dimension::Y, 0., 1.); 0792 CHECK_RANGE_CSYSTEMINDEX(plot, 1, Dimension::X, 0., 1.); 0793 CHECK_RANGE_CSYSTEMINDEX(plot, 1, Dimension::Y, 0., 1.); 0794 const Range<double> plotSceneRangeX = {plot->dataRect().x(), plot->dataRect().x() + plot->dataRect().width()}; 0795 const Range<double> plotSceneRangeY = {plot->dataRect().y() + plot->dataRect().height(), plot->dataRect().y()}; 0796 0797 double bx = plotSceneRangeX.size() / (1 - 0); 0798 double ax = plotSceneRangeX.start() - bx * 0; 0799 0800 double by = plotSceneRangeY.size() / (1 - 0); 0801 double ay = plotSceneRangeY.start() - by * 0; 0802 0803 CHECK_SCALE_PLOT(plot, 0, Dimension::X, ax, bx, 0); 0804 CHECK_SCALE_PLOT(plot, 0, Dimension::Y, ay, by, 0); 0805 CHECK_SCALE_PLOT(plot, 1, Dimension::X, ax, bx, 0); 0806 CHECK_SCALE_PLOT(plot, 1, Dimension::Y, ay, by, 0); 0807 } 0808 0809 // Set range of the unused y range 0810 Range<double> range; 0811 range.setStart(0); // Both are set to the same value 0812 range.setEnd(0); // Both are set to the same value 0813 range.setFormat(RangeT::Format::Numeric); 0814 range.setAutoScale(false); 0815 range.setScale(RangeT::Scale::Linear); 0816 0817 { 0818 // plot->setRange(Dimension::Y, 1, range); // does not work 0819 // Implementation of setRange() must be used, because setRange() uses check to check if 0820 // the range is valid, which it isn't in this test. To test neverthless and not removing a test 0821 // use directly the implementation 0822 int index = 1; 0823 auto dimension = Dimension::Y; 0824 auto otherValue = range; 0825 auto plotPrivate = plot->d_func(); 0826 plotPrivate->setRangeDirty(dimension, index, true); 0827 auto tmp = plotPrivate->rangeConst(dimension, index); 0828 plotPrivate->setRange(dimension, index, otherValue); 0829 otherValue = tmp; 0830 plotPrivate->retransformScale(dimension, index, true); 0831 Dimension dim_other = Dimension::Y; 0832 if (dimension == Dimension::Y) 0833 dim_other = Dimension::X; 0834 0835 QVector<int> scaledIndices; 0836 for (int i = 0; i < plotPrivate->q->coordinateSystemCount(); i++) { 0837 auto cs = plotPrivate->q->coordinateSystem(i); 0838 auto index_other = cs->index(dim_other); 0839 if (cs->index(dimension) == index && scaledIndices.indexOf(index_other) == -1) { 0840 scaledIndices << index_other; 0841 if (plotPrivate->q->autoScale(dim_other, index_other) && plotPrivate->q->scaleAuto(dim_other, index_other, false)) 0842 plotPrivate->retransformScale(dim_other, index_other); 0843 } 0844 } 0845 plotPrivate->q->WorksheetElementContainer::retransform(); 0846 Q_EMIT plotPrivate->q->rangeChanged(dimension, index, plotPrivate->rangeConst(dimension, index)); 0847 } 0848 0849 // Recalculate scales is triggered 0850 { 0851 QCOMPARE(plot->coordinateSystemCount(), 2); 0852 0853 CHECK_RANGE_CSYSTEMINDEX(plot, 0, Dimension::X, 0., 1.); 0854 CHECK_RANGE_CSYSTEMINDEX(plot, 0, Dimension::Y, 0., 1.); 0855 CHECK_RANGE_CSYSTEMINDEX(plot, 1, Dimension::X, 0., 1.); 0856 CHECK_RANGE_CSYSTEMINDEX(plot, 1, Dimension::Y, 0., 0.); 0857 const Range<double> plotSceneRangeX = {plot->dataRect().x(), plot->dataRect().x() + plot->dataRect().width()}; 0858 const Range<double> plotSceneRangeY = {plot->dataRect().y() + plot->dataRect().height(), plot->dataRect().y()}; 0859 0860 double bx = plotSceneRangeX.size() / (1 - 0); 0861 double ax = plotSceneRangeX.start() - bx * 0; 0862 0863 double by = plotSceneRangeY.size() / (1 - 0); 0864 double ay = plotSceneRangeY.start() - by * 0; 0865 0866 CHECK_SCALE_PLOT(plot, 0, Dimension::X, ax, bx, 0); 0867 CHECK_SCALE_PLOT(plot, 0, Dimension::Y, ay, by, 0); 0868 // Don't care what the second cSystem has, because it is invalid 0869 // CHECK_SCALE_PLOT(plot, 1, Dimension::X, ax, bx, 0); 0870 // CHECK_SCALE_PLOT(plot, 1, Dimension::Y, ay, by, 0); 0871 } 0872 0873 QCOMPARE(plot->mouseMode(), CartesianPlot::MouseMode::ZoomXSelection); 0874 plot->mousePressZoomSelectionMode(QPointF(0.2, -150), -1); 0875 plot->mouseMoveZoomSelectionMode(QPointF(0.6, 100), -1); 0876 plot->mouseReleaseZoomSelectionMode(-1); 0877 0878 { 0879 QCOMPARE(plot->coordinateSystemCount(), 2); 0880 0881 CHECK_RANGE_CSYSTEMINDEX(plot, 0, Dimension::X, 0.2, 0.6); 0882 CHECK_RANGE_CSYSTEMINDEX(plot, 0, Dimension::Y, 0., 1.); 0883 CHECK_RANGE_CSYSTEMINDEX(plot, 1, Dimension::X, 0.2, 0.6); 0884 CHECK_RANGE_CSYSTEMINDEX(plot, 1, Dimension::Y, 0., 0.); 0885 const Range<double> plotSceneRangeX = {plot->dataRect().x(), plot->dataRect().x() + plot->dataRect().width()}; 0886 const Range<double> plotSceneRangeY = {plot->dataRect().y() + plot->dataRect().height(), plot->dataRect().y()}; 0887 0888 double bx = plotSceneRangeX.size() / (0.6 - 0.2); 0889 double ax = plotSceneRangeX.start() - bx * 0.2; 0890 0891 double by = plotSceneRangeY.size() / (1 - 0); 0892 double ay = plotSceneRangeY.start() - by * 0; 0893 0894 CHECK_SCALE_PLOT(plot, 0, Dimension::X, ax, bx, 0); 0895 CHECK_SCALE_PLOT(plot, 0, Dimension::Y, ay, by, 0); 0896 // Don't care what the second cSystem has, because it is invalid 0897 // CHECK_SCALE_PLOT(plot, 1, Dimension::X, ax, bx, 0); 0898 // CHECK_SCALE_PLOT(plot, 1, Dimension::Y, ay, by, 0); 0899 } 0900 } 0901 0902 void CartesianPlotTest::autoScaleFitCurveCalculation() { 0903 Project project; 0904 0905 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0906 project.addChild(worksheet); 0907 auto* view = dynamic_cast<WorksheetView*>(worksheet->view()); 0908 QVERIFY(view != nullptr); 0909 view->initActions(); // needed by SET_CARTESIAN_MOUSE_MODE() 0910 0911 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0912 worksheet->addChild(plot); 0913 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0914 plot->setNiceExtend(false); 0915 0916 auto* equationCurve{new XYEquationCurve(QStringLiteral("f(x)"))}; 0917 equationCurve->setCoordinateSystemIndex(plot->defaultCoordinateSystemIndex()); 0918 plot->addChild(equationCurve); 0919 0920 XYEquationCurve::EquationData data; 0921 data.min = QStringLiteral("0"); 0922 data.max = QStringLiteral("1"); 0923 data.count = 10; 0924 data.expression1 = QStringLiteral("x"); 0925 equationCurve->setEquationData(data); 0926 equationCurve->recalculate(); 0927 0928 CHECK_RANGE(plot, equationCurve, Dimension::X, 0., 1.); 0929 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 1.); 0930 0931 auto* fitCurve = new XYFitCurve(QStringLiteral("Fit")); 0932 fitCurve->setCoordinateSystemIndex(plot->defaultCoordinateSystemIndex()); 0933 plot->addChild(fitCurve); 0934 0935 XYFitCurve::FitData f; 0936 f.autoRange = false; 0937 f.fitRange = Range<double>(0, 1); 0938 f.autoEvalRange = false; 0939 f.evalRange = Range<double>(0, 3); // larger than fit range 0940 f.modelCategory = nsl_fit_model_basic; 0941 f.modelType = nsl_fit_model_polynomial; 0942 f.degree = 1; // linear 0943 f.model = QStringLiteral("c0 + c1*x"); 0944 fitCurve->initFitData(f); // Important, otherwise paramNames gets not filled 0945 fitCurve->setFitData(f); 0946 fitCurve->setDataSourceType(XYAnalysisCurve::DataSourceType::Curve); 0947 fitCurve->setDataSourceCurve(equationCurve); 0948 fitCurve->recalculate(); 0949 0950 CHECK_RANGE(plot, equationCurve, Dimension::X, 0., 3.); 0951 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 3.); 0952 } 0953 0954 QTEST_MAIN(CartesianPlotTest)