File indexing completed on 2024-04-21 03:48:05
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 void CartesianPlotTest::wheelEventCenterAxes() { 0955 Project project; 0956 0957 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0958 project.addChild(worksheet); 0959 auto* view = dynamic_cast<WorksheetView*>(worksheet->view()); 0960 QVERIFY(view != nullptr); 0961 view->initMenus(); // needed by SET_CARTESIAN_MOUSE_MODE() 0962 0963 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0964 worksheet->addChild(plot); 0965 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0966 plot->setNiceExtend(false); 0967 0968 auto* equationCurve{new XYEquationCurve(QStringLiteral("f(x)"))}; 0969 equationCurve->setCoordinateSystemIndex(plot->defaultCoordinateSystemIndex()); 0970 plot->addChild(equationCurve); 0971 0972 XYEquationCurve::EquationData data; 0973 data.min = QStringLiteral("0"); 0974 data.max = QStringLiteral("10"); 0975 data.count = 10; 0976 data.expression1 = QStringLiteral("x"); 0977 equationCurve->setEquationData(data); 0978 equationCurve->recalculate(); 0979 0980 CHECK_RANGE(plot, equationCurve, Dimension::X, 0., 10.); 0981 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 10.); 0982 0983 plot->m_zoomFactor = 2; 0984 plot->setNiceExtend(false); 0985 const auto& rect = plot->dataRect(); 0986 0987 int signalEmittedCounter = 0; 0988 connect(plot, 0989 &CartesianPlot::wheelEventSignal, 0990 [&signalEmittedCounter](const QPointF& sceneRelPos, int delta, int xIndex, int yIndex, bool considerDimension, Dimension dim) { 0991 signalEmittedCounter++; 0992 if (signalEmittedCounter == 1) { 0993 QCOMPARE(sceneRelPos.x(), 0.5); 0994 QCOMPARE(sceneRelPos.y(), 0.5); 0995 QVERIFY(delta > 0); 0996 QCOMPARE(xIndex, 0); 0997 QCOMPARE(yIndex, 0); 0998 QCOMPARE(considerDimension, true); 0999 QCOMPARE(dim, Dimension::X); 1000 } else { 1001 QCOMPARE(sceneRelPos.x(), 0.5); 1002 QCOMPARE(sceneRelPos.y(), 0.5); 1003 QVERIFY(delta < 0); 1004 QCOMPARE(xIndex, 0); 1005 QCOMPARE(yIndex, 0); 1006 QCOMPARE(considerDimension, true); 1007 QCOMPARE(dim, Dimension::Y); 1008 } 1009 }); 1010 1011 const auto& axes = plot->children<Axis>(); 1012 QCOMPARE(axes.length(), 2); 1013 QCOMPARE(axes.at(0)->name(), QStringLiteral("x")); 1014 QCOMPARE(axes.at(1)->name(), QStringLiteral("y")); 1015 auto* xAxis = axes.at(0); 1016 auto* yAxis = axes.at(1); 1017 1018 plot->enableAutoScale(Dimension::X, 0, false); 1019 plot->enableAutoScale(Dimension::Y, 0, false); 1020 1021 xAxis->setSelected(true); 1022 QGraphicsSceneWheelEvent event; 1023 event.setPos(QPointF(rect.center().x(), rect.center().y())); 1024 event.setDelta(10); // value not important, only sign 1025 plot->d_func()->wheelEvent(&event); 1026 CHECK_RANGE(plot, equationCurve, Dimension::X, 2.5, 7.5); 1027 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 10.); 1028 QCOMPARE(signalEmittedCounter, 1); 1029 1030 xAxis->setSelected(false); 1031 yAxis->setSelected(true); 1032 event.setPos(QPointF(rect.center().x(), rect.center().y())); 1033 event.setDelta(-10); // value not important, only sign 1034 plot->d_func()->wheelEvent(&event); 1035 CHECK_RANGE(plot, equationCurve, Dimension::X, 2.5, 7.5); 1036 CHECK_RANGE(plot, equationCurve, Dimension::Y, -5., 15.0); 1037 QCOMPARE(signalEmittedCounter, 2); 1038 } 1039 1040 void CartesianPlotTest::wheelEventNotCenter() { 1041 Project project; 1042 1043 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1044 project.addChild(worksheet); 1045 auto* view = dynamic_cast<WorksheetView*>(worksheet->view()); 1046 QVERIFY(view != nullptr); 1047 view->initMenus(); // needed by SET_CARTESIAN_MOUSE_MODE() 1048 1049 auto* plot = new CartesianPlot(QStringLiteral("plot")); 1050 worksheet->addChild(plot); 1051 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1052 plot->setNiceExtend(false); 1053 1054 auto* equationCurve{new XYEquationCurve(QStringLiteral("f(x)"))}; 1055 equationCurve->setCoordinateSystemIndex(plot->defaultCoordinateSystemIndex()); 1056 plot->addChild(equationCurve); 1057 1058 XYEquationCurve::EquationData data; 1059 data.min = QStringLiteral("0"); 1060 data.max = QStringLiteral("10"); 1061 data.count = 10; 1062 data.expression1 = QStringLiteral("x"); 1063 equationCurve->setEquationData(data); 1064 equationCurve->recalculate(); 1065 1066 CHECK_RANGE(plot, equationCurve, Dimension::X, 0., 10.); 1067 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 10.); 1068 1069 plot->m_zoomFactor = 2; 1070 plot->setNiceExtend(false); 1071 const auto& rect = plot->dataRect(); 1072 1073 const auto& axes = plot->children<Axis>(); 1074 QCOMPARE(axes.length(), 2); 1075 QCOMPARE(axes.at(0)->name(), QStringLiteral("x")); 1076 QCOMPARE(axes.at(1)->name(), QStringLiteral("y")); 1077 auto* xAxis = axes.at(0); 1078 // const auto* yAxis = axes.at(1); 1079 1080 int signalEmittedCounter = 0; 1081 connect(plot, 1082 &CartesianPlot::wheelEventSignal, 1083 [&signalEmittedCounter](const QPointF& sceneRelPos, int delta, int xIndex, int yIndex, bool considerDimension, Dimension dim) { 1084 signalEmittedCounter++; 1085 QCOMPARE(sceneRelPos.x(), 0.75); 1086 QCOMPARE(sceneRelPos.y(), 0.2); 1087 QVERIFY(delta > 0); 1088 QCOMPARE(xIndex, 0); 1089 QCOMPARE(yIndex, 0); 1090 QCOMPARE(considerDimension, true); 1091 QCOMPARE(dim, Dimension::X); 1092 }); 1093 1094 xAxis->setSelected(true); 1095 QGraphicsSceneWheelEvent event; 1096 event.setPos(QPointF(rect.left() + rect.width() * 3 / 4, rect.top() + rect.height() * 0.8)); 1097 event.setDelta(10); // value not important, only sign 1098 plot->d_func()->wheelEvent(&event); 1099 CHECK_RANGE(plot, equationCurve, Dimension::X, 3.75, 8.75); 1100 CHECK_RANGE(plot, equationCurve, Dimension::Y, 10. / 3., 8.8888888888888888); 1101 QCOMPARE(signalEmittedCounter, 1); 1102 } 1103 1104 void CartesianPlotTest::wheelEventOutsideTopLeft() { 1105 Project project; 1106 1107 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1108 project.addChild(worksheet); 1109 auto* view = dynamic_cast<WorksheetView*>(worksheet->view()); 1110 QVERIFY(view != nullptr); 1111 view->initMenus(); // needed by SET_CARTESIAN_MOUSE_MODE() 1112 1113 auto* plot = new CartesianPlot(QStringLiteral("plot")); 1114 worksheet->addChild(plot); 1115 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1116 plot->setNiceExtend(false); 1117 1118 auto* equationCurve{new XYEquationCurve(QStringLiteral("f(x)"))}; 1119 equationCurve->setCoordinateSystemIndex(plot->defaultCoordinateSystemIndex()); 1120 plot->addChild(equationCurve); 1121 1122 XYEquationCurve::EquationData data; 1123 data.min = QStringLiteral("0"); 1124 data.max = QStringLiteral("10"); 1125 data.count = 10; 1126 data.expression1 = QStringLiteral("x"); 1127 equationCurve->setEquationData(data); 1128 equationCurve->recalculate(); 1129 1130 CHECK_RANGE(plot, equationCurve, Dimension::X, 0., 10.); 1131 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 10.); 1132 1133 plot->m_zoomFactor = 2; 1134 plot->setNiceExtend(false); 1135 const auto& rect = plot->dataRect(); 1136 1137 int signalEmittedCounter = 0; 1138 connect(plot, 1139 &CartesianPlot::wheelEventSignal, 1140 [&signalEmittedCounter](const QPointF& sceneRelPos, int delta, int xIndex, int yIndex, bool considerDimension, Dimension dim) { 1141 signalEmittedCounter++; 1142 QCOMPARE(sceneRelPos.x(), -0.2); 1143 QCOMPARE(sceneRelPos.y(), 1.3); 1144 QVERIFY(delta > 0); 1145 Q_UNUSED(xIndex); 1146 Q_UNUSED(yIndex); 1147 QCOMPARE(considerDimension, false); 1148 Q_UNUSED(dim); 1149 }); 1150 1151 QGraphicsSceneWheelEvent event; 1152 event.setPos(QPointF(rect.left() - 140, rect.top() - 210)); 1153 event.setDelta(10); // value not important, only sign 1154 plot->d_func()->wheelEvent(&event); 1155 CHECK_RANGE(plot, equationCurve, Dimension::X, -1., 4.); 1156 CHECK_RANGE(plot, equationCurve, Dimension::Y, 6.5, 11.5); 1157 QCOMPARE(signalEmittedCounter, 1); 1158 } 1159 1160 void CartesianPlotTest::wheelEventOutsideBottomRight() { 1161 Project project; 1162 1163 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1164 project.addChild(worksheet); 1165 auto* view = dynamic_cast<WorksheetView*>(worksheet->view()); 1166 QVERIFY(view != nullptr); 1167 view->initMenus(); // needed by SET_CARTESIAN_MOUSE_MODE() 1168 1169 auto* plot = new CartesianPlot(QStringLiteral("plot")); 1170 worksheet->addChild(plot); 1171 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1172 plot->setNiceExtend(false); 1173 1174 auto* equationCurve{new XYEquationCurve(QStringLiteral("f(x)"))}; 1175 equationCurve->setCoordinateSystemIndex(plot->defaultCoordinateSystemIndex()); 1176 plot->addChild(equationCurve); 1177 1178 XYEquationCurve::EquationData data; 1179 data.min = QStringLiteral("0"); 1180 data.max = QStringLiteral("10"); 1181 data.count = 10; 1182 data.expression1 = QStringLiteral("x"); 1183 equationCurve->setEquationData(data); 1184 equationCurve->recalculate(); 1185 1186 CHECK_RANGE(plot, equationCurve, Dimension::X, 0., 10.); 1187 CHECK_RANGE(plot, equationCurve, Dimension::Y, 0., 10.); 1188 1189 plot->m_zoomFactor = 2; 1190 plot->setNiceExtend(false); 1191 const auto& rect = plot->dataRect(); 1192 1193 int signalEmittedCounter = 0; 1194 connect(plot, 1195 &CartesianPlot::wheelEventSignal, 1196 [&signalEmittedCounter](const QPointF& sceneRelPos, int delta, int xIndex, int yIndex, bool considerDimension, Dimension dim) { 1197 signalEmittedCounter++; 1198 QCOMPARE(sceneRelPos.x(), 1.4); 1199 QCOMPARE(sceneRelPos.y(), -0.7); 1200 QVERIFY(delta > 0); 1201 Q_UNUSED(xIndex); 1202 Q_UNUSED(yIndex); 1203 QCOMPARE(considerDimension, false); 1204 Q_UNUSED(dim); 1205 }); 1206 1207 QGraphicsSceneWheelEvent event; 1208 event.setPos(QPointF(rect.right() + 280, rect.bottom() + 490)); 1209 event.setDelta(10); // value not important, only sign 1210 plot->d_func()->wheelEvent(&event); 1211 CHECK_RANGE(plot, equationCurve, Dimension::X, 7., 12.); 1212 CHECK_RANGE(plot, equationCurve, Dimension::Y, -3.5, 1.5); 1213 QCOMPARE(signalEmittedCounter, 1); 1214 } 1215 1216 void CartesianPlotTest::spreadsheetRemoveRows() { 1217 Project project; 1218 1219 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1220 project.addChild(worksheet); 1221 1222 auto* plot = new CartesianPlot(QStringLiteral("plot")); 1223 worksheet->addChild(plot); 1224 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1225 plot->setNiceExtend(false); 1226 1227 auto* sheet = new Spreadsheet(QStringLiteral("data"), false); 1228 project.addChild(sheet); 1229 sheet->setColumnCount(2); 1230 1231 const auto& columns = sheet->children<Column>(); 1232 QCOMPARE(columns.count(), 2); 1233 Column* xColumn = columns.at(0); 1234 Column* yColumn = columns.at(1); 1235 1236 xColumn->replaceValues(-1, 1237 { 1238 1., 1239 2., 1240 3., 1241 4., 1242 5., 1243 }); 1244 yColumn->replaceValues(-1, 1245 { 1246 0., 1247 4., 1248 6., 1249 8., 1250 10., 1251 }); 1252 1253 auto* curve = new XYCurve(QStringLiteral("curve")); 1254 plot->addChild(curve); 1255 curve->setXColumn(xColumn); 1256 curve->setYColumn(yColumn); 1257 1258 CHECK_RANGE(plot, curve, Dimension::X, 1., 5.); 1259 CHECK_RANGE(plot, curve, Dimension::Y, 0., 10.); 1260 1261 sheet->removeRows(4, 1); 1262 1263 CHECK_RANGE(plot, curve, Dimension::X, 1., 4.); 1264 CHECK_RANGE(plot, curve, Dimension::Y, 0., 8.); 1265 1266 sheet->undoStack()->undo(); 1267 1268 CHECK_RANGE(plot, curve, Dimension::X, 1., 5.); 1269 CHECK_RANGE(plot, curve, Dimension::Y, 0., 10.); 1270 } 1271 1272 void CartesianPlotTest::spreadsheetInsertRows() { 1273 Project project; 1274 1275 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1276 project.addChild(worksheet); 1277 1278 auto* plot = new CartesianPlot(QStringLiteral("plot")); 1279 worksheet->addChild(plot); 1280 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1281 plot->setNiceExtend(false); 1282 1283 auto* sheet = new Spreadsheet(QStringLiteral("data"), false); 1284 project.addChild(sheet); 1285 sheet->setColumnCount(2); 1286 1287 const auto& columns = sheet->children<Column>(); 1288 QCOMPARE(columns.count(), 2); 1289 Column* xColumn = columns.at(0); 1290 Column* yColumn = columns.at(1); 1291 1292 xColumn->replaceValues(-1, 1293 { 1294 1., 1295 2., 1296 3., 1297 4., 1298 5., 1299 }); 1300 yColumn->replaceValues(-1, 1301 { 1302 0., 1303 4., 1304 6., 1305 8., 1306 10., 1307 }); 1308 1309 auto* curve = new XYCurve(QStringLiteral("curve")); 1310 plot->addChild(curve); 1311 curve->setXColumn(xColumn); 1312 curve->setYColumn(yColumn); 1313 1314 CHECK_RANGE(plot, curve, Dimension::X, 1., 5.); 1315 CHECK_RANGE(plot, curve, Dimension::Y, 0., 10.); 1316 1317 sheet->insertRows(4, 1); 1318 QCOMPARE(xColumn->rowCount(), 6); 1319 QCOMPARE(yColumn->rowCount(), 6); 1320 1321 xColumn->replaceValues(5, {13}); 1322 yColumn->replaceValues(5, {25}); 1323 1324 CHECK_RANGE(plot, curve, Dimension::X, 1., 13.); 1325 CHECK_RANGE(plot, curve, Dimension::Y, 0., 25.); 1326 1327 sheet->undoStack()->undo(); // xColumn replace values 1328 sheet->undoStack()->undo(); // yColumn replace values 1329 sheet->undoStack()->undo(); // spreadsheet insertRows 1330 1331 CHECK_RANGE(plot, curve, Dimension::X, 1., 5.); 1332 CHECK_RANGE(plot, curve, Dimension::Y, 0., 10.); 1333 } 1334 1335 QTEST_MAIN(CartesianPlotTest)