File indexing completed on 2025-04-20 03:34:14
0001 /* 0002 File : XYCurveTest.cpp 0003 Project : LabPlot 0004 Description : Tests for XYCurve 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2021 Martin Marmsoler <martin.marmsoler@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "RetransformTest.h" 0012 0013 #include "backend/core/Project.h" 0014 #include "backend/core/column/Column.h" 0015 #include "backend/datasources/filters/AsciiFilter.h" 0016 #include "backend/spreadsheet/Spreadsheet.h" 0017 #include "backend/worksheet/Worksheet.h" 0018 #include "backend/worksheet/plots/cartesian/AxisPrivate.h" 0019 #include "backend/worksheet/plots/cartesian/BarPlot.h" 0020 #include "backend/worksheet/plots/cartesian/BoxPlot.h" 0021 #include "backend/worksheet/plots/cartesian/CartesianPlot.h" 0022 #include "backend/worksheet/plots/cartesian/Histogram.h" 0023 #include "backend/worksheet/plots/cartesian/XYCurve.h" 0024 #include "backend/worksheet/plots/cartesian/XYCurvePrivate.h" 0025 #include "backend/worksheet/plots/cartesian/XYEquationCurve.h" 0026 #include "commonfrontend/worksheet/WorksheetView.h" 0027 #include "kdefrontend/dockwidgets/AxisDock.h" 0028 #include "kdefrontend/dockwidgets/CartesianPlotDock.h" 0029 #include "kdefrontend/dockwidgets/XYCurveDock.h" 0030 0031 #include <QAction> 0032 0033 #define COMPARE(actual, expected, message) \ 0034 do { \ 0035 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) { \ 0036 qDebug() << message; \ 0037 return; \ 0038 } \ 0039 } while (false) 0040 0041 using Dimension = CartesianCoordinateSystem::Dimension; 0042 0043 void RetransformTest::initTestCase() { 0044 // needed in order to have the signals triggered by SignallingUndoCommand, see LabPlot.cpp 0045 // TODO: redesign/remove this 0046 qRegisterMetaType<const AbstractAspect*>("const AbstractAspect*"); 0047 qRegisterMetaType<const AbstractColumn*>("const AbstractColumn*"); 0048 } 0049 0050 void RetransformTest::TestLoadProject() { 0051 RetransformCallCounter c; 0052 Project project; 0053 0054 // Does not work during load. 0055 // connect(&project, &Project::aspectAdded, &c, &RetransformCallCounter::aspectAdded); 0056 0057 project.load(QFINDTESTDATA(QLatin1String("data/p1.lml"))); 0058 0059 QHash<QString, int> h = {{QStringLiteral("Project/Worksheet/xy-plot"), 1}, 0060 {QStringLiteral("Project/Worksheet/xy-plot/x"), 1}, 0061 {QStringLiteral("Project/Worksheet/xy-plot/y"), 1}, 0062 {QStringLiteral("Project/Worksheet/xy-plot/sin"), 1}, 0063 {QStringLiteral("Project/Worksheet/xy-plot/cos"), 1}, 0064 {QStringLiteral("Project/Worksheet/xy-plot/tan"), 1}, 0065 {QStringLiteral("Project/Worksheet/xy-plot/y-axis"), 1}, 0066 {QStringLiteral("Project/Worksheet/xy-plot/legend"), 1}, 0067 {QStringLiteral("Project/Worksheet/xy-plot/plotImage"), 1}, 0068 {QStringLiteral("Project/Worksheet/xy-plot/plotText"), 1}, 0069 {QStringLiteral("Project/Worksheet/Text Label"), 1}, 0070 {QStringLiteral("Project/Worksheet/Image"), 1}, 0071 {QStringLiteral("Project/Worksheet/plot2"), 1}, 0072 {QStringLiteral("Project/Worksheet/plot2/x"), 1}, 0073 {QStringLiteral("Project/Worksheet/plot2/y"), 1}, 0074 {QStringLiteral("Project/Worksheet/plot2/xy-curve"), 1}}; 0075 0076 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0077 for (auto& child : children) { 0078 int expectedCallCount = 0; 0079 const QString& path = child->path(); 0080 if (h.contains(path)) 0081 expectedCallCount = h.value(path); 0082 COMPARE(c.callCount(child), expectedCallCount, path); 0083 } 0084 } 0085 0086 // Problem in this project was that the second axis labels are not loaded. Zooming in/out once shows the correct range 0087 void RetransformTest::TestLoadProject2() { 0088 QLocale::setDefault(QLocale::C); // . as decimal separator 0089 RetransformCallCounter c; 0090 Project project; 0091 0092 project.load(QFINDTESTDATA(QLatin1String("data/bars_dis_004.lml"))); 0093 0094 QHash<QString, int> h = {{QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet"), 1}, 0095 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/x"), 1}, 0096 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/y"), 1}, 0097 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/x2"), 1}, 0098 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/y2"), 1}, 0099 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/Frequency"), 1}, 0100 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/Cumulative"), 1}, 0101 {QStringLiteral("Project/Worksheet - Spreadsheet/Plot - Spreadsheet/legend"), 1}}; 0102 0103 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0104 for (auto& child : children) { 0105 int expectedCallCount = 0; 0106 const QString& path = child->path(); 0107 if (h.contains(path)) 0108 expectedCallCount = h.value(path); 0109 COMPARE(c.callCount(child), expectedCallCount, path); 0110 } 0111 0112 // check axis ranges 0113 auto axes = project.children(AspectType::Axis, AbstractAspect::ChildIndexFlag::Recursive); 0114 QCOMPARE(axes.length(), 4); 0115 auto* xAxis = axes.at(0); 0116 auto* xAxis2 = axes.at(1); 0117 auto* yAxis1 = axes.at(2); 0118 auto* yAxis2 = axes.at(3); 0119 0120 QCOMPARE(xAxis->name(), QStringLiteral("x")); 0121 QCOMPARE(xAxis2->name(), QStringLiteral("x2")); 0122 QCOMPARE(yAxis1->name(), QStringLiteral("y")); 0123 QCOMPARE(yAxis2->name(), QStringLiteral("y2")); 0124 0125 // xAxis2 does not have any labels 0126 QVector<QString> refString = {QStringLiteral("161.2"), 0127 QStringLiteral("166.7"), 0128 QStringLiteral("172.2"), 0129 QStringLiteral("177.8"), 0130 QStringLiteral("183.3"), 0131 QStringLiteral("188.8"), 0132 QStringLiteral("194.4")}; 0133 COMPARE_STRING_VECTORS(static_cast<Axis*>(xAxis)->tickLabelStrings(), refString); 0134 QVector<double> ref = {0, 20, 40, 60, 80, 100}; 0135 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(yAxis1)->tickLabelValues(), ref); 0136 ref = {0, 0.2, 0.4, 0.6, 0.8, 1.0}; 0137 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(yAxis2)->tickLabelValues(), ref); 0138 } 0139 0140 void RetransformTest::TestResizeWindows() { 0141 RetransformCallCounter c; 0142 Project project; 0143 project.load(QFINDTESTDATA(QLatin1String("data/p1.lml"))); 0144 0145 const auto& worksheets = project.children(AspectType::Worksheet); 0146 QCOMPARE(worksheets.count(), 1); 0147 auto worksheet = static_cast<Worksheet*>(worksheets.at(0)); 0148 auto* view = static_cast<WorksheetView*>(worksheet->view()); 0149 0150 view->resize(100, 100); 0151 view->processResize(); 0152 0153 for (const auto& child : project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive)) 0154 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0155 0156 view->resize(1000, 1000); 0157 view->processResize(); 0158 0159 // Check that every element is exactly called once 0160 QHash<QString, int> h = {{QStringLiteral("Project/Worksheet/xy-plot"), 1}, 0161 {QStringLiteral("Project/Worksheet/xy-plot/x"), 1}, 0162 {QStringLiteral("Project/Worksheet/xy-plot/y"), 1}, 0163 {QStringLiteral("Project/Worksheet/xy-plot/sin"), 1}, 0164 {QStringLiteral("Project/Worksheet/xy-plot/cos"), 1}, 0165 {QStringLiteral("Project/Worksheet/xy-plot/tan"), 1}, 0166 {QStringLiteral("Project/Worksheet/xy-plot/y-axis"), 1}, 0167 {QStringLiteral("Project/Worksheet/xy-plot/legend"), 1}, 0168 {QStringLiteral("Project/Worksheet/xy-plot/plotImage"), 1}, 0169 {QStringLiteral("Project/Worksheet/xy-plot/plotText"), 1}, 0170 //{QStringLiteral("Project/Worksheet/Text Label"), 1}, // TODO: turn on when fixed 0171 //{QStringLiteral("Project/Worksheet/Image"), 1}, // TODO: turn on when fixed 0172 {QStringLiteral("Project/Worksheet/plot2"), 1}, 0173 {QStringLiteral("Project/Worksheet/plot2/x"), 1}, 0174 {QStringLiteral("Project/Worksheet/plot2/y"), 1}, 0175 {QStringLiteral("Project/Worksheet/plot2/xy-curve"), 1}}; 0176 0177 QCOMPARE(c.elementLogCount(false), h.count()); 0178 QHash<QString, int>::const_iterator i; 0179 for (i = h.constBegin(); i != h.constEnd(); ++i) 0180 QCOMPARE(c.callCount(i.key()), 1); 0181 } 0182 0183 /*! 0184 * \brief RetransformTest::TestZoomSelectionAutoscale 0185 * Check that retransform and retransform scale is called correctly during zoom and autoscale. Check 0186 * also the number of calls of the retransforms 0187 */ 0188 void RetransformTest::TestZoomSelectionAutoscale() { 0189 RetransformCallCounter c; 0190 Project project; 0191 0192 project.load(QFINDTESTDATA(QLatin1String("data/p1.lml"))); 0193 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0194 0195 // Spreadsheet "Spreadsheet" 0196 // Column "x" 0197 // Column "sin" 0198 // Column "cos" 0199 // Column "tan" 0200 // Worksheet "Worksheet" 0201 // CartesianPlot "xy-plot" 0202 // Axis "x" 0203 // Axis "y" 0204 // XYCurve "sin" 0205 // XYCurve "cos" 0206 // XYCurve "tan" 0207 // Axis "y-axis" 0208 // Legend "legend" 0209 // TextLabel "plotText" 0210 // Image "plotImage" 0211 // TextLabel "Text Label" 0212 // Image "Image" 0213 // --- Second plot 0214 // CartesianPlot "plot2" 0215 // Axis "x" 0216 // Axis "y" 0217 // XYCurve "xy-curve" 0218 QCOMPARE(children.length(), 22); 0219 for (const auto& child : children) 0220 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0221 0222 for (const auto& plot : project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive)) { 0223 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0224 } 0225 0226 auto* worksheet = project.child<Worksheet>(0); 0227 QVERIFY(worksheet); 0228 0229 auto* view = static_cast<WorksheetView*>(worksheet->view()); 0230 QVERIFY(view); 0231 0232 auto* plot = worksheet->child<CartesianPlot>(0); 0233 QVERIFY(plot); 0234 QCOMPARE(plot->name(), QLatin1String("xy-plot")); 0235 0236 auto* plot2 = worksheet->child<CartesianPlot>(1); 0237 QVERIFY(plot2); 0238 QCOMPARE(plot2->name(), QLatin1String("plot2")); 0239 0240 QCOMPARE(plot->childCount<XYCurve>(), 3); 0241 QCOMPARE(plot->child<XYCurve>(0)->name(), QStringLiteral("sin")); 0242 QCOMPARE(plot->child<XYCurve>(0)->coordinateSystemIndex(), 0); 0243 QCOMPARE(plot->child<XYCurve>(1)->name(), QStringLiteral("cos")); 0244 QCOMPARE(plot->child<XYCurve>(1)->coordinateSystemIndex(), 0); 0245 QCOMPARE(plot->child<XYCurve>(2)->name(), QStringLiteral("tan")); 0246 QCOMPARE(plot->child<XYCurve>(2)->coordinateSystemIndex(), 1); 0247 0248 QAction a(nullptr); 0249 a.setData(static_cast<int>(CartesianPlot::MouseMode::ZoomXSelection)); 0250 view->cartesianPlotMouseModeChanged(&a); 0251 0252 QCOMPARE(c.elementLogCount(false), 0); 0253 QVERIFY(c.calledExact(0, false)); 0254 0255 Q_EMIT plot->mousePressZoomSelectionModeSignal(QPointF(0.2, -150)); 0256 Q_EMIT plot->mouseMoveZoomSelectionModeSignal(QPointF(0.6, 100)); 0257 Q_EMIT plot->mouseReleaseZoomSelectionModeSignal(); 0258 0259 // x and y are called only once 0260 QCOMPARE(c.logsXScaleRetransformed.count(), 2); // 2 plots with each one x axis 0261 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, plot); 0262 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 0263 QCOMPARE(c.logsXScaleRetransformed.at(1).plot, plot2); 0264 QCOMPARE(c.logsXScaleRetransformed.at(1).index, 0); 0265 QCOMPARE(c.logsYScaleRetransformed.count(), 0266 3); // there are two vertical ranges (sin, cos and tan range) for the first plot and one y axis for the second plot 0267 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, plot); 0268 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 0269 QCOMPARE(c.logsYScaleRetransformed.at(1).plot, plot); 0270 QCOMPARE(c.logsYScaleRetransformed.at(1).index, 1); 0271 QCOMPARE(c.logsYScaleRetransformed.at(2).plot, plot2); 0272 QCOMPARE(c.logsYScaleRetransformed.at(2).index, 0); 0273 0274 // Check that every element is exactly called once 0275 // plot it self does not change so retransform is not called on cartesianplotPrivate 0276 QStringList list = { 0277 QStringLiteral("Project/Worksheet/xy-plot/x"), 0278 QStringLiteral("Project/Worksheet/xy-plot/y"), 0279 QStringLiteral("Project/Worksheet/xy-plot/sin"), 0280 QStringLiteral("Project/Worksheet/xy-plot/cos"), 0281 QStringLiteral("Project/Worksheet/xy-plot/tan"), 0282 QStringLiteral("Project/Worksheet/xy-plot/y-axis"), 0283 // not neccesary to retransform legend, but is difficult to 0284 // distinguish so let it in, because it does not cost that much performance 0285 QStringLiteral("Project/Worksheet/xy-plot/legend"), 0286 QStringLiteral("Project/Worksheet/xy-plot/plotText"), 0287 QStringLiteral("Project/Worksheet/xy-plot/plotImage"), 0288 // second plot starting 0289 QStringLiteral("Project/Worksheet/plot2/x"), 0290 QStringLiteral("Project/Worksheet/plot2/y"), 0291 QStringLiteral("Project/Worksheet/plot2/xy-curve"), 0292 }; 0293 QCOMPARE(c.elementLogCount(false), list.count()); 0294 for (auto& s : list) 0295 QCOMPARE(c.callCount(s), 1); 0296 0297 c.resetRetransformCount(); 0298 view->selectItem(plot->graphicsItem()); 0299 a.setData(static_cast<int>(CartesianPlot::NavigationOperation::ScaleAutoX)); 0300 view->cartesianPlotNavigationChanged(&a); 0301 0302 QCOMPARE(c.elementLogCount(false), list.count()); 0303 for (auto& s : list) 0304 QCOMPARE(c.callCount(s), 1); 0305 0306 // x and y are called only once 0307 QCOMPARE(c.logsXScaleRetransformed.count(), 2); // 2 plots with each one x axis 0308 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, plot); 0309 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); // first x axis of first plot 0310 QCOMPARE(c.logsXScaleRetransformed.at(1).plot, plot2); 0311 QCOMPARE(c.logsXScaleRetransformed.at(1).index, 0); // first x axis of second plot 0312 QCOMPARE(c.logsYScaleRetransformed.count(), 0313 3); // there are two vertical ranges (sin, cos and tan range) for the first plot and one y axis for the second plot 0314 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, plot); 0315 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); // first y axis of first plot 0316 QCOMPARE(c.logsYScaleRetransformed.at(1).plot, plot); 0317 QCOMPARE(c.logsYScaleRetransformed.at(1).index, 1); // second y axis of first plot 0318 QCOMPARE(c.logsYScaleRetransformed.at(2).plot, plot2); 0319 QCOMPARE(c.logsYScaleRetransformed.at(2).index, 0); // first y axis of second plot 0320 } 0321 0322 /*! 0323 * \brief RetransformTest::TestZoomAutoscaleSingleYRange 0324 * Having two coordinatesystems cSystem1 and cSystem2 with a common x Range 0325 * cSystem1 has automatic scaling of y Range turned on, cSystem2 not 0326 * When zoom x Selection is done, the y Range of cSystem1 shall be autoscaled, 0327 * but not the y Range of cSystem2 0328 * Nice extends should not apply! 0329 */ 0330 void RetransformTest::TestZoomAutoscaleSingleYRange() { 0331 Project project; 0332 0333 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0334 project.addChild(worksheet); 0335 0336 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0337 worksheet->addChild(plot); 0338 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0339 plot->setNiceExtend(true); // Important must be on! 0340 0341 // Create new cSystem2 0342 Range<double> yRange; 0343 yRange.setFormat(RangeT::Format::Numeric); 0344 plot->addYRange(yRange); 0345 CartesianCoordinateSystem* cSystem2 = new CartesianCoordinateSystem(plot); 0346 cSystem2->setIndex(Dimension::X, 0); 0347 cSystem2->setIndex(Dimension::Y, 1); 0348 plot->addCoordinateSystem(cSystem2); 0349 0350 // Generate data and 0351 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0352 project.addChild(sheet); 0353 sheet->setColumnCount(3); 0354 sheet->setRowCount(11); 0355 sheet->column(0)->setColumnMode(AbstractColumn::ColumnMode::Double); 0356 sheet->column(1)->setColumnMode(AbstractColumn::ColumnMode::Double); 0357 sheet->column(2)->setColumnMode(AbstractColumn::ColumnMode::Double); 0358 0359 for (int i = 0; i < sheet->rowCount(); i++) { 0360 sheet->column(0)->setValueAt(i, i); 0361 sheet->column(1)->setValueAt(i, i + 1000 + 0.3); 0362 sheet->column(2)->setValueAt(i, -i + 0.1); // This 0.1 is important! 0363 } 0364 0365 auto* curve1 = new XYCurve(QStringLiteral("curve1")); 0366 plot->addChild(curve1); 0367 curve1->setCoordinateSystemIndex(0); 0368 curve1->setXColumn(sheet->column(0)); 0369 curve1->setYColumn(sheet->column(1)); 0370 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0371 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0372 QCOMPARE(plot->rangeFormat(Dimension::Y, 1), RangeT::Format::Numeric); 0373 0374 auto* curve2 = new XYCurve(QStringLiteral("curve2")); 0375 plot->addChild(curve2); 0376 curve2->setCoordinateSystemIndex(1); 0377 curve2->setXColumn(sheet->column(0)); 0378 curve2->setYColumn(sheet->column(2)); 0379 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0380 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0381 QCOMPARE(plot->rangeFormat(Dimension::Y, 1), RangeT::Format::Numeric); 0382 0383 CHECK_RANGE(plot, curve1, Dimension::X, 0., 10.); 0384 CHECK_RANGE(plot, curve1, Dimension::Y, 1000., 1011.); // Nice extend applied 0385 CHECK_RANGE(plot, curve2, Dimension::X, 0., 10.); 0386 CHECK_RANGE(plot, curve2, Dimension::Y, -10., 1.); 0387 0388 plot->enableAutoScale(Dimension::Y, 1, false); // disable autoscale for second y range 0389 0390 auto r = plot->range(Dimension::Y, 1); 0391 r.setStart(-9.9); 0392 r.setEnd(0.1); 0393 plot->setRange(Dimension::Y, 1, r); 0394 0395 CHECK_RANGE(plot, curve1, Dimension::X, 0., 10.); 0396 CHECK_RANGE(plot, curve1, Dimension::Y, 1000., 1011.); 0397 CHECK_RANGE(plot, curve2, Dimension::X, 0., 10.); 0398 CHECK_RANGE(plot, curve2, Dimension::Y, -9.9, 0.1); 0399 0400 QAction a(nullptr); 0401 a.setData(static_cast<int>(CartesianPlot::MouseMode::ZoomXSelection)); 0402 auto* view = static_cast<WorksheetView*>(worksheet->view()); 0403 QVERIFY(view); 0404 view->initActions(); 0405 view->cartesianPlotMouseModeChanged(&a); 0406 0407 view->setCartesianPlotActionMode(Worksheet::CartesianPlotActionMode::ApplyActionToAllX); 0408 0409 // Zoom selection 0410 Q_EMIT plot->mousePressZoomSelectionModeSignal(QPointF(2, 0)); 0411 Q_EMIT plot->mouseMoveZoomSelectionModeSignal(QPointF(3, 100)); 0412 Q_EMIT plot->mouseReleaseZoomSelectionModeSignal(); 0413 0414 CHECK_RANGE(plot, curve1, Dimension::X, 2., 3.); 0415 CHECK_RANGE(plot, curve1, Dimension::Y, 1002.2, 1003.3); // Nice Extend applied 0416 CHECK_RANGE(plot, curve2, Dimension::X, 2., 3.); 0417 CHECK_RANGE(plot, curve2, Dimension::Y, -9.9, 0.1); // Not changed, because autoscale is turned off 0418 } 0419 0420 /*! 0421 * \brief RetransformTest::TestZoomAutoscaleSingleXRange 0422 * Having two coordinatesystems cSystem1 and cSystem2 with a common y Range 0423 * cSystem1 has automatic scaling of x Range turned on, cSystem2 not 0424 * When zoom y Selection is done, the x Range of cSystem1 shall be autoscaled, 0425 * but not the x Range of cSystem2 0426 * Nice extends should not apply! 0427 */ 0428 void RetransformTest::TestZoomAutoscaleSingleXRange() { 0429 Project project; 0430 0431 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0432 project.addChild(worksheet); 0433 0434 auto* plot = new CartesianPlot(QStringLiteral("plot")); 0435 worksheet->addChild(plot); 0436 plot->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0437 plot->setNiceExtend(true); // Important must be on! 0438 0439 // Create new cSystem2 0440 Range<double> xRange; 0441 xRange.setFormat(RangeT::Format::Numeric); 0442 plot->addXRange(xRange); 0443 CartesianCoordinateSystem* cSystem2 = new CartesianCoordinateSystem(plot); 0444 cSystem2->setIndex(Dimension::X, 1); 0445 cSystem2->setIndex(Dimension::Y, 0); 0446 plot->addCoordinateSystem(cSystem2); 0447 0448 // Generate data and 0449 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0450 project.addChild(sheet); 0451 sheet->setColumnCount(3); 0452 sheet->setRowCount(11); 0453 sheet->column(0)->setColumnMode(AbstractColumn::ColumnMode::Double); 0454 sheet->column(1)->setColumnMode(AbstractColumn::ColumnMode::Double); 0455 sheet->column(2)->setColumnMode(AbstractColumn::ColumnMode::Double); 0456 0457 for (int i = 0; i < sheet->rowCount(); i++) { 0458 sheet->column(0)->setValueAt(i, i); 0459 sheet->column(1)->setValueAt(i, i + 1000 + 0.3); 0460 sheet->column(2)->setValueAt(i, -i + 0.1); // This 0.1 is important! 0461 } 0462 0463 auto* curve1 = new XYCurve(QStringLiteral("curve1")); 0464 plot->addChild(curve1); 0465 curve1->setCoordinateSystemIndex(0); 0466 curve1->setXColumn(sheet->column(1)); 0467 curve1->setYColumn(sheet->column(0)); 0468 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0469 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0470 QCOMPARE(plot->rangeFormat(Dimension::X, 1), RangeT::Format::Numeric); 0471 0472 auto* curve2 = new XYCurve(QStringLiteral("curve2")); 0473 plot->addChild(curve2); 0474 curve2->setCoordinateSystemIndex(1); 0475 curve2->setXColumn(sheet->column(2)); 0476 curve2->setYColumn(sheet->column(0)); 0477 QCOMPARE(plot->rangeFormat(Dimension::X, 0), RangeT::Format::Numeric); 0478 QCOMPARE(plot->rangeFormat(Dimension::Y, 0), RangeT::Format::Numeric); 0479 QCOMPARE(plot->rangeFormat(Dimension::X, 1), RangeT::Format::Numeric); 0480 0481 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 10.); 0482 CHECK_RANGE(plot, curve1, Dimension::X, 1000., 1011.); // Nice extend applied 0483 CHECK_RANGE(plot, curve2, Dimension::Y, 0., 10.); 0484 CHECK_RANGE(plot, curve2, Dimension::X, -10., 1.); 0485 0486 plot->enableAutoScale(Dimension::X, 1, false); // disable autoscale for second y range 0487 0488 auto r = plot->range(Dimension::X, 1); 0489 r.setStart(-9.9); 0490 r.setEnd(0.1); 0491 plot->setRange(Dimension::X, 1, r); 0492 0493 CHECK_RANGE(plot, curve1, Dimension::Y, 0., 10.); 0494 CHECK_RANGE(plot, curve1, Dimension::X, 1000., 1011.); 0495 CHECK_RANGE(plot, curve2, Dimension::Y, 0., 10.); 0496 CHECK_RANGE(plot, curve2, Dimension::X, -9.9, 0.1); 0497 0498 QAction a(nullptr); 0499 a.setData(static_cast<int>(CartesianPlot::MouseMode::ZoomYSelection)); 0500 auto* view = static_cast<WorksheetView*>(worksheet->view()); 0501 QVERIFY(view); 0502 view->initActions(); 0503 view->cartesianPlotMouseModeChanged(&a); 0504 0505 view->setCartesianPlotActionMode(Worksheet::CartesianPlotActionMode::ApplyActionToAllY); 0506 0507 // Zoom selection 0508 Q_EMIT plot->mousePressZoomSelectionModeSignal(QPointF(0, 2)); 0509 Q_EMIT plot->mouseMoveZoomSelectionModeSignal(QPointF(100, 3)); 0510 Q_EMIT plot->mouseReleaseZoomSelectionModeSignal(); 0511 0512 CHECK_RANGE(plot, curve1, Dimension::Y, 2., 3.); 0513 CHECK_RANGE(plot, curve1, Dimension::X, 1002.2, 1003.3); // Nice Extend applied 0514 CHECK_RANGE(plot, curve2, Dimension::Y, 2., 3.); 0515 CHECK_RANGE(plot, curve2, Dimension::X, -9.9, 0.1); // Not changed, because autoscale is turned off 0516 } 0517 0518 /*! 0519 * \brief RetransformTest::TestPadding 0520 * Check that during a padding change retransform and retransform scale is called 0521 */ 0522 void RetransformTest::TestPadding() { 0523 RetransformCallCounter c; 0524 Project project; 0525 0526 project.load(QFINDTESTDATA(QLatin1String("data/p1.lml"))); 0527 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0528 0529 // Spreadsheet "Spreadsheet" 0530 // Column "x" 0531 // Column "sin" 0532 // Column "cos" 0533 // Column "tan" 0534 // Worksheet "Worksheet" 0535 // CartesianPlot "xy-plot" 0536 // Axis "x" 0537 // Axis "y" 0538 // XYCurve "sin" 0539 // XYCurve "cos" 0540 // XYCurve "tan" 0541 // Axis "y-axis" 0542 // Legend "legend" 0543 // TextLabel "plotText" 0544 // Image "plotImage" 0545 // TextLabel "Text Label" 0546 // Image "Image" 0547 // --- Second plot 0548 // CartesianPlot "plot2" 0549 // Axis "x" 0550 // Axis "y" 0551 // XYCurve "xy-curve" 0552 QCOMPARE(children.length(), 22); 0553 for (const auto& child : children) 0554 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0555 0556 for (const auto& plot : project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive)) 0557 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0558 0559 auto* worksheet = project.child<Worksheet>(0); 0560 QVERIFY(worksheet); 0561 0562 auto* view = static_cast<WorksheetView*>(worksheet->view()); 0563 QVERIFY(view); 0564 0565 auto* plot = worksheet->child<CartesianPlot>(0); 0566 QVERIFY(plot); 0567 QCOMPARE(plot->name(), QLatin1String("xy-plot")); 0568 0569 // Check that every element is exactly called once 0570 // TODO: set to 6. legend should not retransform 0571 // plot it self does not change so retransform is not called on cartesianplotPrivate 0572 QStringList list = {QStringLiteral("Project/Worksheet/xy-plot"), // datarect changed, so plot must also be retransformed 0573 QStringLiteral("Project/Worksheet/xy-plot/x"), 0574 QStringLiteral("Project/Worksheet/xy-plot/y"), 0575 QStringLiteral("Project/Worksheet/xy-plot/sin"), 0576 QStringLiteral("Project/Worksheet/xy-plot/cos"), 0577 QStringLiteral("Project/Worksheet/xy-plot/tan"), 0578 QStringLiteral("Project/Worksheet/xy-plot/y-axis"), 0579 QStringLiteral("Project/Worksheet/xy-plot/legend"), 0580 QStringLiteral("Project/Worksheet/xy-plot/plotText"), 0581 QStringLiteral("Project/Worksheet/xy-plot/plotImage")}; 0582 double hPad = plot->horizontalPadding(); 0583 plot->setHorizontalPadding(hPad + 10); 0584 0585 QCOMPARE(c.elementLogCount(false), list.count()); 0586 for (auto& s : list) 0587 QCOMPARE(c.callCount(s), 1); 0588 0589 // x and y are called only once 0590 QCOMPARE(c.logsXScaleRetransformed.count(), 1); 0591 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, plot); 0592 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 0593 QCOMPARE(c.logsYScaleRetransformed.count(), 2); // there are two vertical ranges (sin,cos and tan range) 0594 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, plot); 0595 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 0596 QCOMPARE(c.logsYScaleRetransformed.at(1).plot, plot); 0597 QCOMPARE(c.logsYScaleRetransformed.at(1).index, 1); 0598 0599 c.resetRetransformCount(); 0600 0601 list = QStringList({// data rect of the plot does not change, so retransforming the 0602 // plot is not needed 0603 QStringLiteral("Project/Worksheet/xy-plot/x"), 0604 QStringLiteral("Project/Worksheet/xy-plot/y"), 0605 QStringLiteral("Project/Worksheet/xy-plot/sin"), 0606 QStringLiteral("Project/Worksheet/xy-plot/cos"), 0607 QStringLiteral("Project/Worksheet/xy-plot/tan"), 0608 QStringLiteral("Project/Worksheet/xy-plot/y-axis"), 0609 QStringLiteral("Project/Worksheet/xy-plot/legend"), 0610 QStringLiteral("Project/Worksheet/xy-plot/plotText"), 0611 QStringLiteral("Project/Worksheet/xy-plot/plotImage")}); 0612 plot->navigate(-1, CartesianPlot::NavigationOperation::ScaleAuto); 0613 0614 QCOMPARE(c.elementLogCount(false), list.count()); 0615 for (auto& s : list) 0616 QCOMPARE(c.callCount(s), 1); 0617 0618 // x and y are already scaled due to the change of padding 0619 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 0620 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 0621 } 0622 0623 void RetransformTest::TestCopyPastePlot() { 0624 Project project; 0625 auto* ws = new Worksheet(QStringLiteral("Worksheet")); 0626 QVERIFY(ws != nullptr); 0627 project.addChild(ws); 0628 0629 auto* p = new CartesianPlot(QStringLiteral("plot")); 0630 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0631 QVERIFY(p != nullptr); 0632 ws->addChild(p); 0633 0634 auto* ws2 = new Worksheet(QStringLiteral("Worksheet2")); 0635 QVERIFY(ws2 != nullptr); 0636 project.addChild(ws2); 0637 0638 RetransformCallCounter c; 0639 0640 p->copy(); 0641 ws2->paste(true); 0642 0643 auto plots = ws2->children(AspectType::CartesianPlot); 0644 QCOMPARE(plots.count(), 1); 0645 0646 // Check that the plot was retransformed after pasting 0647 QCOMPARE(c.callCount(plots.at(0)), 1); 0648 } 0649 0650 void RetransformTest::TestAddCurve() { 0651 Project project; 0652 auto* ws = new Worksheet(QStringLiteral("Worksheet")); 0653 QVERIFY(ws != nullptr); 0654 project.addChild(ws); 0655 0656 auto* p = new CartesianPlot(QStringLiteral("plot")); 0657 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0658 QVERIFY(p != nullptr); 0659 ws->addChild(p); 0660 0661 RetransformCallCounter c; 0662 0663 p->addChild(new XYEquationCurve(QLatin1String("curve"))); 0664 0665 // check that plot will be recalculated if a curve will be added 0666 QCOMPARE(c.callCount(p), 1); 0667 0668 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0669 0670 // Project/Worksheet 0671 // Project/Worksheet/plot 0672 // Project/Worksheet/plot/x 0673 // Project/Worksheet/plot/y 0674 // Project/Worksheet/plot/f(x) // equation curve 0675 QCOMPARE(children.length(), 5); 0676 for (const auto& child : children) 0677 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0678 0679 for (const auto& plot : project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive)) 0680 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0681 0682 c.resetRetransformCount(); 0683 0684 auto equationCurves = p->children(AspectType::XYEquationCurve); 0685 QCOMPARE(equationCurves.count(), 1); 0686 auto* equationCurve = static_cast<XYEquationCurve*>(equationCurves.at(0)); 0687 XYEquationCurve::EquationData data; 0688 data.count = 100; 0689 data.expression1 = QStringLiteral("x"); 0690 data.expression2 = QString(); 0691 data.min = QStringLiteral("0"); 0692 data.max = QStringLiteral("10"); 0693 data.type = XYEquationCurve::EquationType::Cartesian; 0694 equationCurve->setEquationData(data); 0695 0696 auto list = 0697 QStringList({QStringLiteral("Project/Worksheet/plot/x"), QStringLiteral("Project/Worksheet/plot/y"), QStringLiteral("Project/Worksheet/plot/f(x)")}); 0698 QCOMPARE(c.elementLogCount(false), list.count()); 0699 QCOMPARE(c.callCount(list.at(0)), 1); 0700 QCOMPARE(c.callCount(list.at(1)), 1); 0701 QCOMPARE(c.callCount(list.at(2)), 0); 0702 0703 // x and y are called only once 0704 QCOMPARE(c.logsXScaleRetransformed.count(), 1); 0705 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, p); 0706 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 0707 QCOMPARE(c.logsYScaleRetransformed.count(), 1); 0708 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, p); 0709 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 0710 } 0711 0712 void RetransformTest::TestBarPlotOrientation() { 0713 RetransformCallCounter c; 0714 Project project; 0715 0716 project.load(QFINDTESTDATA(QLatin1String("data/barplot_test.lml"))); 0717 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0718 0719 // Spreadsheet "Spreadsheet" 0720 // Column "labels" 0721 // Column "1" 0722 // Column "2" 0723 // Column "3" 0724 // Column "4" 0725 // Worksheet "Worksheet" 0726 // CartesianPlot "xy-plot" 0727 // Axis "x" 0728 // Axis "x2" 0729 // Axis "y" 0730 // Axis "y2" 0731 // BarPlot "BarPlot" 0732 QCOMPARE(children.length(), 13); 0733 for (const auto& child : children) 0734 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0735 0736 for (const auto& plot : project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive)) 0737 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0738 0739 auto barplots = project.children(AspectType::BarPlot, AbstractAspect::ChildIndexFlag::Recursive); 0740 QCOMPARE(barplots.length(), 1); 0741 auto barplot = static_cast<BarPlot*>(barplots.at(0)); 0742 QCOMPARE(barplot->name(), QStringLiteral("Bar Plot")); 0743 0744 // Trigger retransform 0745 barplot->setOrientation(BarPlot::Orientation::Horizontal); 0746 0747 auto* worksheet = project.child<Worksheet>(0); 0748 QVERIFY(worksheet); 0749 auto* plot = worksheet->child<CartesianPlot>(0); 0750 QVERIFY(plot); 0751 QCOMPARE(plot->name(), QLatin1String("xy-plot")); 0752 0753 // x and y are called only once 0754 QCOMPARE(c.logsXScaleRetransformed.count(), 1); // one plot with 2 x-Axes but both are using the same range so 1 0755 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, plot); 0756 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 0757 QCOMPARE(c.logsYScaleRetransformed.count(), 1); // one plot with 2 x-Axes but both are using the same range so 1 0758 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, plot); 0759 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 0760 } 0761 0762 void RetransformTest::TestZoom() { 0763 RetransformCallCounter c; 0764 Project project; 0765 0766 auto* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0767 sheet->setColumnCount(2); 0768 sheet->setRowCount(100); 0769 0770 QVector<int> xData; 0771 QVector<double> yData; 0772 for (int i = 0; i < 100; i++) { 0773 xData.append(i); 0774 yData.append(i); 0775 } 0776 auto* xColumn = sheet->column(0); 0777 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 0778 xColumn->replaceInteger(0, xData); 0779 auto* yColumn = sheet->column(1); 0780 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 0781 yColumn->replaceValues(0, yData); 0782 0783 project.addChild(sheet); 0784 0785 auto* worksheet = new Worksheet(QStringLiteral("Worksheet - Spreadsheet")); 0786 project.addChild(worksheet); 0787 0788 auto* p = new CartesianPlot(QStringLiteral("Plot - Spreadsheet")); 0789 p->setType(CartesianPlot::Type::FourAxes); // Otherwise no axis are created 0790 worksheet->addChild(p); 0791 0792 auto* curve = new XYCurve(QStringLiteral("curve")); 0793 p->addChild(curve); 0794 curve->setXColumn(xColumn); 0795 curve->setYColumn(yColumn); 0796 0797 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0798 0799 // Spreadsheet "Spreadsheet" 0800 // Column "1" 0801 // Column "2" 0802 // Worksheet "Worksheet-Spreadsheet" 0803 // CartesianPlot "Plot-Spreadsheet" 0804 // Axis "x" 0805 // Axis "x2" 0806 // Axis "y" 0807 // Axis "y2" 0808 // XYCurve "curve" 0809 QCOMPARE(children.length(), 10); 0810 for (const auto& child : children) 0811 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0812 0813 auto plots = project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive); 0814 QCOMPARE(plots.length(), 1); 0815 auto* plot = static_cast<CartesianPlot*>(plots[0]); 0816 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0817 0818 plot->zoomInX(); 0819 0820 // x and y are called only once 0821 QCOMPARE(c.logsXScaleRetransformed.count(), 1); // one plot with 2 x-Axes but both are using the same range so 1 0822 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, plot); 0823 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 0824 QCOMPARE(c.logsYScaleRetransformed.count(), 1); // one plot with 2 x-Axes but both are using the same range so 1 0825 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, plot); 0826 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 0827 } 0828 0829 void RetransformTest::TestImportCSV() { 0830 Project project; 0831 auto* ws = new Worksheet(QStringLiteral("Worksheet")); 0832 QVERIFY(ws != nullptr); 0833 project.addChild(ws); 0834 0835 Spreadsheet* spreadsheet = new Spreadsheet(QStringLiteral("test"), false); 0836 spreadsheet->setColumnCount(2); 0837 spreadsheet->setRowCount(3); 0838 0839 auto* xCol = spreadsheet->column(0); 0840 xCol->replaceValues(0, QVector<double>({1, 2, 3})); 0841 0842 auto* yCol = spreadsheet->column(1); 0843 yCol->replaceValues(0, QVector<double>({2, 3, 4})); 0844 0845 QCOMPARE(spreadsheet->rowCount(), 3); 0846 QCOMPARE(spreadsheet->columnCount(), 2); 0847 0848 project.addChild(spreadsheet); 0849 auto* p = new CartesianPlot(QStringLiteral("plot")); 0850 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 0851 QVERIFY(p != nullptr); 0852 ws->addChild(p); 0853 0854 auto* curve = new XYCurve(QStringLiteral("xy-curve")); 0855 curve->setXColumn(xCol); 0856 curve->setYColumn(yCol); 0857 p->addChild(curve); 0858 0859 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0860 0861 RetransformCallCounter c; 0862 // Worksheet "Worksheet" 0863 // CartesianPlot "plot" 0864 // Axis "x" 0865 // Axis "y" 0866 // XYCurve "xy-curve" 0867 // Spreadsheet "test" 0868 // Column "1" 0869 // Column "2" 0870 QCOMPARE(children.length(), 8); 0871 for (const auto& child : children) { 0872 qDebug() << child->name(); 0873 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0874 } 0875 0876 for (const auto& plot : project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive)) 0877 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0878 0879 // check axis ranges 0880 auto axes = p->children(AspectType::Axis, AbstractAspect::ChildIndexFlag::Recursive); 0881 QCOMPARE(axes.length(), 2); 0882 auto* xAxis = axes.at(0); 0883 QVector<double> ref = {1, 1.5, 2, 2.5, 3}; 0884 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(xAxis)->tickLabelValues(), ref); 0885 auto* yAxis = axes.at(1); 0886 ref = {2, 2.5, 3, 3.5, 4}; 0887 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(yAxis)->tickLabelValues(), ref); 0888 0889 QTemporaryFile file; 0890 QCOMPARE(file.open(), true); 0891 QVERIFY(file.write("1,2\n10,10\n20,20\n30,30\n") > 0); 0892 file.close(); 0893 0894 AsciiFilter filter; 0895 filter.setHeaderLine(1); 0896 filter.readDataFromFile(file.fileName(), spreadsheet, AbstractFileFilter::ImportMode::Replace); 0897 0898 QCOMPARE(spreadsheet->rowCount(), 3); 0899 QCOMPARE(spreadsheet->columnCount(), 2); 0900 0901 xCol = spreadsheet->column(0); 0902 QCOMPARE(xCol->name(), QStringLiteral("1")); 0903 QCOMPARE(xCol->valueAt(0), 10); 0904 QCOMPARE(xCol->valueAt(1), 20); 0905 QCOMPARE(xCol->valueAt(2), 30); 0906 0907 yCol = spreadsheet->column(1); 0908 QCOMPARE(yCol->name(), QStringLiteral("2")); 0909 QCOMPARE(yCol->valueAt(0), 10); 0910 QCOMPARE(yCol->valueAt(1), 20); 0911 QCOMPARE(yCol->valueAt(2), 30); 0912 0913 ref = {10, 15, 20, 25, 30}; 0914 auto tickLabelValues = static_cast<Axis*>(xAxis)->tickLabelValues(); 0915 COMPARE_DOUBLE_VECTORS(tickLabelValues, ref); 0916 ref = {10, 15, 20, 25, 30}; 0917 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(yAxis)->tickLabelValues(), ref); 0918 0919 // x and y are called only once 0920 QCOMPARE(c.logsXScaleRetransformed.count(), 1); // one plot with 1 x-Axis 0921 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, p); 0922 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 0923 QCOMPARE(c.logsYScaleRetransformed.count(), 1); // one plot with 1 x-Axis 0924 QCOMPARE(c.logsYScaleRetransformed.at(0).plot, p); 0925 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 0926 0927 auto list = QStringList( 0928 {QStringLiteral("Project/Worksheet/plot/x"), QStringLiteral("Project/Worksheet/plot/y"), QStringLiteral("Project/Worksheet/plot/xy-curve")}); 0929 QCOMPARE(c.elementLogCount(false), list.count()); 0930 for (auto& s : list) { 0931 qDebug() << s; 0932 QCOMPARE(c.callCount(s), 1); 0933 } 0934 } 0935 0936 void RetransformTest::TestSetScale() { 0937 RetransformCallCounter c; 0938 Project project; 0939 0940 auto* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 0941 sheet->setColumnCount(2); 0942 sheet->setRowCount(100); 0943 0944 QVector<int> xData; 0945 QVector<double> yData; 0946 for (int i = 0; i < 100; i++) { 0947 xData.append(i); 0948 yData.append(i); 0949 } 0950 auto* xColumn = sheet->column(0); 0951 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 0952 xColumn->replaceInteger(0, xData); 0953 auto* yColumn = sheet->column(1); 0954 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 0955 yColumn->replaceValues(0, yData); 0956 0957 project.addChild(sheet); 0958 0959 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 0960 project.addChild(worksheet); 0961 0962 auto* p = new CartesianPlot(QStringLiteral("Plot")); 0963 p->setType(CartesianPlot::Type::FourAxes); // Otherwise no axis are created 0964 worksheet->addChild(p); 0965 0966 auto* curve = new XYCurve(QStringLiteral("curve")); 0967 p->addChild(curve); 0968 curve->setXColumn(xColumn); 0969 curve->setYColumn(yColumn); 0970 0971 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 0972 0973 // Spreadsheet "Spreadsheet" 0974 // Column "1" 0975 // Column "2" 0976 // Worksheet "Worksheet" 0977 // CartesianPlot "Plot" 0978 // Axis "x" 0979 // Axis "x2" 0980 // Axis "y" 0981 // Axis "y2" 0982 // XYCurve "curve" 0983 QCOMPARE(children.length(), 10); 0984 for (const auto& child : children) 0985 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 0986 0987 auto plots = project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive); 0988 QCOMPARE(plots.length(), 1); 0989 auto* plot = static_cast<CartesianPlot*>(plots[0]); 0990 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 0991 0992 c.resetRetransformCount(); 0993 0994 auto list = QStringList({// data rect of the plot does not change, so retransforming the 0995 // plot is not needed 0996 QStringLiteral("Project/Worksheet/Plot/x"), 0997 QStringLiteral("Project/Worksheet/Plot/x2"), 0998 QStringLiteral("Project/Worksheet/Plot/y"), 0999 QStringLiteral("Project/Worksheet/Plot/y2"), 1000 QStringLiteral("Project/Worksheet/Plot/curve")}); 1001 1002 plot->setRangeScale(Dimension::X, 0, RangeT::Scale::Log10); 1003 1004 QCOMPARE(c.elementLogCount(false), list.count()); 1005 for (auto& s : list) 1006 QCOMPARE(c.callCount(s), 1); 1007 1008 // x and y are called only once 1009 QCOMPARE(c.logsXScaleRetransformed.count(), 1); 1010 QCOMPARE(c.logsXScaleRetransformed.at(0).plot, plot); 1011 QCOMPARE(c.logsXScaleRetransformed.at(0).index, 0); 1012 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1013 } 1014 1015 void RetransformTest::TestChangePlotRange() { 1016 RetransformCallCounter c; 1017 Project project; 1018 1019 auto* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 1020 sheet->setColumnCount(2); 1021 sheet->setRowCount(100); 1022 1023 QVector<int> xData; 1024 QVector<double> yData; 1025 for (int i = 0; i < 100; i++) { 1026 xData.append(i); 1027 yData.append(i); 1028 } 1029 auto* xColumn = sheet->column(0); 1030 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 1031 xColumn->replaceInteger(0, xData); 1032 auto* yColumn = sheet->column(1); 1033 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 1034 yColumn->replaceValues(0, yData); 1035 1036 project.addChild(sheet); 1037 1038 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1039 project.addChild(worksheet); 1040 1041 auto* p = new CartesianPlot(QStringLiteral("Plot")); 1042 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1043 worksheet->addChild(p); 1044 1045 auto* curve = new XYCurve(QStringLiteral("curve")); 1046 p->addChild(curve); 1047 curve->setXColumn(xColumn); 1048 curve->setYColumn(yColumn); 1049 1050 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 1051 1052 // Spreadsheet "Spreadsheet" 1053 // Column "1" 1054 // Column "2" 1055 // Worksheet "Worksheet" 1056 // CartesianPlot "Plot" 1057 // Axis "x" 1058 // Axis "y" 1059 // XYCurve "curve" 1060 QCOMPARE(children.length(), 8); 1061 for (const auto& child : children) 1062 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 1063 1064 auto plots = project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive); 1065 QCOMPARE(plots.length(), 1); 1066 auto* plot = static_cast<CartesianPlot*>(plots[0]); 1067 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 1068 1069 c.resetRetransformCount(); 1070 1071 auto list = QStringList({// data rect of the plot does not change, so retransforming the 1072 // plot is not needed 1073 QStringLiteral("Project/Worksheet/Plot/x"), 1074 QStringLiteral("Project/Worksheet/Plot/y"), 1075 QStringLiteral("Project/Worksheet/Plot/curve")}); 1076 1077 CartesianPlotDock dock(nullptr); 1078 dock.setPlots({plot}); 1079 dock.addXRange(); 1080 1081 QCOMPARE(plot->rangeCount(Dimension::X), 2); 1082 1083 dock.autoScaleChanged(Dimension::X, 1, false); 1084 QCOMPARE(plot->autoScale(Dimension::X, 1), false); 1085 1086 dock.minChanged(Dimension::X, 1, 10); 1087 dock.maxChanged(Dimension::X, 1, 20); 1088 1089 // check axis ranges 1090 auto axes = project.children(AspectType::Axis, AbstractAspect::ChildIndexFlag::Recursive); 1091 QCOMPARE(axes.length(), 2); 1092 auto* xAxis = static_cast<Axis*>(axes.at(0)); 1093 auto* yAxis = static_cast<Axis*>(axes.at(1)); 1094 1095 QCOMPARE(xAxis->name(), QStringLiteral("x")); 1096 QCOMPARE(yAxis->name(), QStringLiteral("y")); 1097 1098 // QVector<QString> refString = {"0", "20", "20", "177.8", "183.3", "188.8", "194.4"}; 1099 // COMPARE_STRING_VECTORS(static_cast<Axis*>(xAxis)->tickLabelStrings(), refString); 1100 QVector<double> ref = {0, 20, 40, 60, 80, 100}; 1101 COMPARE_DOUBLE_VECTORS(xAxis->tickLabelValues(), ref); 1102 ref = {0, 20, 40, 60, 80, 100}; 1103 COMPARE_DOUBLE_VECTORS(yAxis->tickLabelValues(), ref); 1104 1105 int linesUpdatedCounter = 0; 1106 connect(curve, &XYCurve::linesUpdated, [&linesUpdatedCounter](const XYCurve*, const QVector<QLineF> lines) { 1107 // One point before and one point after is used therefore it is not 10, 20 1108 // se XYCurvePrivate::updateLines() startIndex--; and endIndex++; 1109 QCOMPARE(lines.at(0).p1().x(), 9); 1110 QCOMPARE(lines.last().p2().x(), 21); 1111 linesUpdatedCounter++; 1112 }); 1113 // switch in first csystem from the first x range to the second x range 1114 dock.PlotRangeChanged(0, Dimension::X, 1); 1115 1116 ref = {10, 12, 14, 16, 18, 20}; 1117 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(xAxis)->tickLabelValues(), ref); 1118 ref = {0, 20, 40, 60, 80, 100}; 1119 COMPARE_DOUBLE_VECTORS(static_cast<Axis*>(yAxis)->tickLabelValues(), ref); 1120 1121 auto dataRect = plot->dataRect(); 1122 1123 // check that lines are starting at the beginning of the datarect 1124 auto line = xAxis->d_func()->lines.at(0); 1125 QCOMPARE(line.p1().x(), dataRect.left()); 1126 QCOMPARE(line.p2().x(), dataRect.right()); 1127 1128 auto lines = curve->d_func()->m_lines; 1129 QCOMPARE(lines.at(0).p1().x(), dataRect.left()); 1130 QCOMPARE(lines.last().p2().x(), dataRect.right()); 1131 1132 QCOMPARE(linesUpdatedCounter, 1); 1133 } 1134 1135 void RetransformTest::TestChangePlotRangeElement() { 1136 // Change the plotrange of one of the elements 1137 1138 RetransformCallCounter c; 1139 Project project; 1140 1141 auto* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 1142 sheet->setColumnCount(2); 1143 sheet->setRowCount(100); 1144 1145 QVector<int> xData; 1146 QVector<double> yData; 1147 for (int i = 0; i < 100; i++) { 1148 xData.append(i); 1149 yData.append(i); 1150 } 1151 auto* xColumn = sheet->column(0); 1152 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 1153 xColumn->replaceInteger(0, xData); 1154 auto* yColumn = sheet->column(1); 1155 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 1156 yColumn->replaceValues(0, yData); 1157 1158 project.addChild(sheet); 1159 1160 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1161 project.addChild(worksheet); 1162 1163 auto* p = new CartesianPlot(QStringLiteral("Plot")); 1164 p->setType(CartesianPlot::Type::FourAxes); // Otherwise no axis are created 1165 worksheet->addChild(p); 1166 1167 auto* curve = new XYCurve(QStringLiteral("curve")); 1168 p->addChild(curve); 1169 curve->setXColumn(xColumn); 1170 curve->setYColumn(yColumn); 1171 1172 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 1173 1174 // Spreadsheet "Spreadsheet" 1175 // Column "1" 1176 // Column "2" 1177 // Worksheet "Worksheet" 1178 // CartesianPlot "Plot" 1179 // Axis "x" 1180 // Axis "x2" 1181 // Axis "y" 1182 // Axis "y2" 1183 // XYCurve "curve" 1184 QCOMPARE(children.length(), 10); 1185 for (const auto& child : children) 1186 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 1187 1188 auto plots = project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive); 1189 QCOMPARE(plots.length(), 1); 1190 auto* plot = static_cast<CartesianPlot*>(plots[0]); 1191 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 1192 1193 // check axes 1194 auto axes = project.children(AspectType::Axis, AbstractAspect::ChildIndexFlag::Recursive); 1195 QCOMPARE(axes.length(), 4); 1196 auto* xAxis1 = static_cast<Axis*>(axes.at(0)); 1197 auto* xAxis2 = static_cast<Axis*>(axes.at(1)); 1198 auto* yAxis1 = static_cast<Axis*>(axes.at(2)); 1199 auto* yAxis2 = static_cast<Axis*>(axes.at(3)); 1200 QCOMPARE(xAxis1->name(), QStringLiteral("x")); 1201 QCOMPARE(xAxis2->name(), QStringLiteral("x2")); 1202 QCOMPARE(yAxis1->name(), QStringLiteral("y")); 1203 QCOMPARE(yAxis2->name(), QStringLiteral("y2")); 1204 1205 auto list = QStringList({// data rect of the plot does not change, so retransforming the 1206 // plot is not needed 1207 QStringLiteral("Project/Worksheet/Plot/x"), 1208 QStringLiteral("Project/Worksheet/Plot/y"), 1209 QStringLiteral("Project/Worksheet/Plot/x2"), 1210 QStringLiteral("Project/Worksheet/Plot/y2"), 1211 QStringLiteral("Project/Worksheet/Plot/curve")}); 1212 1213 CartesianPlotDock dock(nullptr); 1214 dock.setPlots({plot}); 1215 dock.addYRange(); 1216 QCOMPARE(plot->rangeCount(Dimension::Y), 2); 1217 dock.addPlotRange(); 1218 QCOMPARE(plot->coordinateSystemCount(), 2); 1219 1220 dock.autoScaleChanged(Dimension::Y, 1, false); 1221 QCOMPARE(plot->autoScale(Dimension::Y, 1), false); 1222 dock.minChanged(Dimension::Y, 1, 10); 1223 dock.maxChanged(Dimension::Y, 1, 20); 1224 1225 // Csystem1: 1226 // x 0..1 1227 // y 0..1 1228 // Csystem2: 1229 // x 0..1 1230 // y 10..20 1231 1232 c.resetRetransformCount(); 1233 1234 dock.PlotRangeChanged(1, Dimension::Y, 1); 1235 1236 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1237 QCOMPARE(c.logsYScaleRetransformed.count(), 1); 1238 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 1); 1239 1240 QCOMPARE(plot->range(Dimension::X, 0).start(), 0); 1241 QCOMPARE(plot->range(Dimension::X, 0).end(), 100); 1242 QCOMPARE(plot->range(Dimension::Y, 0).start(), 0); 1243 QCOMPARE(plot->range(Dimension::Y, 0).end(), 100); 1244 QCOMPARE(plot->range(Dimension::Y, 1).start(), 10); 1245 QCOMPARE(plot->range(Dimension::Y, 1).end(), 20); 1246 1247 c.resetRetransformCount(); 1248 1249 { 1250 AxisDock d(nullptr); 1251 d.setAxes({yAxis2}); 1252 QCOMPARE(yAxis2->coordinateSystemIndex(), 0); 1253 d.plotRangeChanged(1); // change plotrange of yAxis2 from 0 to 1 1254 QCOMPARE(yAxis2->coordinateSystemIndex(), 1); 1255 } 1256 1257 // the y scale of cSystem1 and the y scale of CSystem2 shall be retransformed, because 1258 // an element switches from y1 to y2 1259 // xScale shall not be retransformed because it is common for both cSystems 1260 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1261 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1262 // QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); // range did not change so retransformScale was not called 1263 // QCOMPARE(c.logsYScaleRetransformed.at(1).index, 1); // range did not change so retransformScale was not called 1264 1265 const auto dataRect = plot->dataRect(); 1266 1267 // Check that both lines go from bottom to top 1268 { 1269 QCOMPARE(yAxis1->d_func()->lines.count(), 1); 1270 const auto line = yAxis1->d_func()->lines.at(0); 1271 QCOMPARE(line.p1().y(), dataRect.bottom()); 1272 QCOMPARE(line.p2().y(), dataRect.top()); 1273 } 1274 1275 { 1276 QCOMPARE(yAxis2->d_func()->lines.count(), 1); 1277 const auto line = yAxis2->d_func()->lines.at(0); 1278 QCOMPARE(line.p1().y(), dataRect.bottom()); 1279 QCOMPARE(line.p2().y(), dataRect.top()); 1280 } 1281 } 1282 1283 void RetransformTest::TestChangePlotRangeElement2() { 1284 // Change the plotrange of one of the elements 1285 1286 RetransformCallCounter c; 1287 Project project; 1288 1289 auto* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 1290 sheet->setColumnCount(4); 1291 sheet->setRowCount(100); 1292 1293 project.addChild(sheet); 1294 1295 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1296 project.addChild(worksheet); 1297 1298 auto* p = new CartesianPlot(QStringLiteral("Plot")); 1299 p->setType(CartesianPlot::Type::FourAxes); // Otherwise no axis are created 1300 worksheet->addChild(p); 1301 p->setNiceExtend(false); 1302 1303 auto* curve = new XYCurve(QStringLiteral("curve")); 1304 p->addChild(curve); 1305 { 1306 QVector<int> xData; 1307 QVector<double> yData; 1308 for (int i = 1; i < 101; i++) { 1309 xData.append(i); 1310 yData.append(i); 1311 } 1312 auto* xColumn = sheet->column(0); 1313 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 1314 xColumn->replaceInteger(0, xData); 1315 auto* yColumn = sheet->column(1); 1316 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 1317 yColumn->replaceValues(0, yData); 1318 curve->setXColumn(xColumn); 1319 curve->setYColumn(yColumn); 1320 } 1321 1322 auto* curve2 = new XYCurve(QStringLiteral("curve2")); 1323 p->addChild(curve2); 1324 { 1325 QVector<int> xData; 1326 QVector<double> yData; 1327 for (int i = 1; i < 31; i++) { // different to the above 1328 xData.append(i); 1329 yData.append(i); 1330 } 1331 auto* xColumn = sheet->column(2); 1332 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 1333 xColumn->replaceInteger(0, xData); 1334 auto* yColumn = sheet->column(3); 1335 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 1336 yColumn->replaceValues(0, yData); 1337 curve2->setXColumn(xColumn); 1338 curve2->setYColumn(yColumn); 1339 } 1340 1341 // SAVE_PROJECT("TestChangePlotRangeElement2.lml"); 1342 1343 QCOMPARE(p->range(Dimension::X, 0).start(), 1); 1344 QCOMPARE(p->range(Dimension::X, 0).end(), 100); 1345 QCOMPARE(p->range(Dimension::Y, 0).start(), 1); 1346 QCOMPARE(p->range(Dimension::Y, 0).end(), 100); 1347 1348 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 1349 1350 // Spreadsheet "Spreadsheet" 1351 // Column "1" 1352 // Column "2" 1353 // Column "3" 1354 // Column "4" 1355 // Worksheet "Worksheet" 1356 // CartesianPlot "Plot" 1357 // Axis "x" 1358 // Axis "x2" 1359 // Axis "y" 1360 // Axis "y2" 1361 // XYCurve "curve" 1362 // XYCurve "curve2" 1363 QCOMPARE(children.length(), 13); 1364 for (const auto& child : children) 1365 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 1366 1367 auto plots = project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive); 1368 QCOMPARE(plots.length(), 1); 1369 auto* plot = static_cast<CartesianPlot*>(plots[0]); 1370 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 1371 1372 // check axis ranges 1373 auto axes = project.children(AspectType::Axis, AbstractAspect::ChildIndexFlag::Recursive); 1374 QCOMPARE(axes.length(), 4); 1375 auto* xAxis1 = static_cast<Axis*>(axes.at(0)); 1376 auto* xAxis2 = static_cast<Axis*>(axes.at(1)); 1377 auto* yAxis1 = static_cast<Axis*>(axes.at(2)); 1378 auto* yAxis2 = static_cast<Axis*>(axes.at(3)); 1379 QCOMPARE(xAxis1->name(), QStringLiteral("x")); 1380 QCOMPARE(xAxis2->name(), QStringLiteral("x2")); 1381 QCOMPARE(yAxis1->name(), QStringLiteral("y")); 1382 QCOMPARE(yAxis2->name(), QStringLiteral("y2")); 1383 1384 auto list = QStringList({// data rect of the plot does not change, so retransforming the 1385 // plot is not needed 1386 QStringLiteral("Project/Worksheet/Plot/x"), 1387 QStringLiteral("Project/Worksheet/Plot/y"), 1388 QStringLiteral("Project/Worksheet/Plot/x2"), 1389 QStringLiteral("Project/Worksheet/Plot/y2"), 1390 QStringLiteral("Project/Worksheet/Plot/curve"), 1391 QStringLiteral("Project/Worksheet/Plot/curve2")}); 1392 1393 CartesianPlotDock dock(nullptr); 1394 dock.setPlots({plot}); 1395 dock.addYRange(); 1396 QCOMPARE(plot->rangeCount(Dimension::Y), 2); 1397 dock.addPlotRange(); 1398 QCOMPARE(plot->coordinateSystemCount(), 2); 1399 1400 c.resetRetransformCount(); 1401 1402 dock.PlotRangeChanged(1, Dimension::Y, 1); // switch for second csystem to y range 2 1403 1404 // No update of the scales, because the range did not change 1405 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1406 QCOMPARE(c.logsYScaleRetransformed.count(), 1); 1407 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 1); // The respective coordinate system must be rescaled 1408 1409 c.resetRetransformCount(); 1410 1411 XYCurveDock curveDock(nullptr); 1412 curveDock.setupGeneral(); 1413 curveDock.setCurves({curve2}); 1414 QCOMPARE(curve2->coordinateSystemIndex(), 0); 1415 curveDock.plotRangeChanged(1); // set curve range to other 1416 QCOMPARE(curve2->coordinateSystemIndex(), 1); 1417 1418 // CSystem1: 1419 // x 1..100 1420 // y 1..100 1421 // CSystem2: 1422 // x 1..100 // bigger 100 > 30 (same xrange as for CSystem1 1423 // y 1..30 1424 1425 QCOMPARE(plot->range(Dimension::X, 0).start(), 1); 1426 QCOMPARE(plot->range(Dimension::X, 0).end(), 100); 1427 QCOMPARE(plot->range(Dimension::Y, 0).start(), 1); 1428 QCOMPARE(plot->range(Dimension::Y, 0).end(), 100); 1429 QCOMPARE(plot->range(Dimension::Y, 1).start(), 1); 1430 QCOMPARE(plot->range(Dimension::Y, 1).end(), 30); 1431 1432 // the y scale of cSystem1 and the y scale of CSystem2 shall be retransformed, because 1433 // cruve2 switches from y1 to y2 1434 // xScale shall not be retransformed because it did not change 1435 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1436 QCOMPARE(c.logsYScaleRetransformed.count(), 1); 1437 // QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); // did not change, because range is already at 1..100 1438 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 1); 1439 1440 const auto dataRect = plot->dataRect(); 1441 1442 // Check that both lines go from bottom to top 1443 { 1444 QCOMPARE(yAxis1->d_func()->lines.count(), 1); 1445 const auto line = yAxis1->d_func()->lines.at(0); 1446 QCOMPARE(line.p1().y(), dataRect.bottom()); 1447 QCOMPARE(line.p2().y(), dataRect.top()); 1448 } 1449 1450 { 1451 QCOMPARE(yAxis2->d_func()->lines.count(), 1); 1452 const auto line = yAxis2->d_func()->lines.at(0); 1453 QCOMPARE(line.p1().y(), dataRect.bottom()); 1454 QCOMPARE(line.p2().y(), dataRect.top()); 1455 } 1456 1457 // Now change cSystemIndex of second yAxis too 1458 c.resetRetransformCount(); 1459 1460 { 1461 AxisDock d(nullptr); 1462 d.setAxes({yAxis2}); 1463 d.plotRangeChanged(1); // change from cSystem1 to cSystem2 1464 } 1465 1466 // the y scale of cSystem1 and the y scale of CSystem2 shall be retransformed, because 1467 // yAxis2 switches from y1 to y2 1468 // xScale shall not be retransformed because it did not change 1469 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1470 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1471 // QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); // range did not change, so retransformScale gets not called 1472 // QCOMPARE(c.logsYScaleRetransformed.at(0).index, 1); // range did not change, so retransformScale gets not called 1473 1474 { 1475 QCOMPARE(yAxis1->d_func()->lines.count(), 1); 1476 const auto line = yAxis1->d_func()->lines.at(0); 1477 QCOMPARE(line.p1().y(), dataRect.bottom()); 1478 QCOMPARE(line.p2().y(), dataRect.top()); 1479 } 1480 1481 { 1482 QCOMPARE(yAxis2->d_func()->lines.count(), 1); 1483 const auto line = yAxis2->d_func()->lines.at(0); 1484 QCOMPARE(line.p1().y(), dataRect.bottom()); 1485 QCOMPARE(line.p2().y(), dataRect.top()); 1486 } 1487 } 1488 1489 void RetransformTest::TestChangePlotRangeElement3() { 1490 // Change the plotrange of one of the elements 1491 // This time curve1 changes csystem 1492 // --> yRange1 and yRange2 have to be transformed 1493 1494 RetransformCallCounter c; 1495 Project project; 1496 1497 auto* sheet = new Spreadsheet(QStringLiteral("Spreadsheet"), false); 1498 sheet->setColumnCount(4); 1499 sheet->setRowCount(100); 1500 1501 project.addChild(sheet); 1502 1503 auto* worksheet = new Worksheet(QStringLiteral("Worksheet")); 1504 project.addChild(worksheet); 1505 1506 auto* p = new CartesianPlot(QStringLiteral("Plot")); 1507 p->setType(CartesianPlot::Type::FourAxes); // Otherwise no axis are created 1508 worksheet->addChild(p); 1509 p->setNiceExtend(false); 1510 1511 auto* curve = new XYCurve(QStringLiteral("curve")); 1512 p->addChild(curve); 1513 { 1514 QVector<int> xData; 1515 QVector<double> yData; 1516 for (int i = 1; i < 101; i++) { 1517 xData.append(i); 1518 yData.append(i); 1519 } 1520 auto* xColumn = sheet->column(0); 1521 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 1522 xColumn->replaceInteger(0, xData); 1523 auto* yColumn = sheet->column(1); 1524 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 1525 yColumn->replaceValues(0, yData); 1526 curve->setXColumn(xColumn); 1527 curve->setYColumn(yColumn); 1528 } 1529 1530 auto* curve2 = new XYCurve(QStringLiteral("curve2")); 1531 p->addChild(curve2); 1532 { 1533 QVector<int> xData; 1534 QVector<double> yData; 1535 for (int i = 1; i < 31; i++) { // different to the above 1536 xData.append(i); 1537 yData.append(i); 1538 } 1539 auto* xColumn = sheet->column(2); 1540 xColumn->setColumnMode(AbstractColumn::ColumnMode::Integer); 1541 xColumn->replaceInteger(0, xData); 1542 auto* yColumn = sheet->column(3); 1543 yColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 1544 yColumn->replaceValues(0, yData); 1545 curve2->setXColumn(xColumn); 1546 curve2->setYColumn(yColumn); 1547 } 1548 1549 // SAVE_PROJECT("TestChangePlotRangeElement2.lml"); 1550 1551 QCOMPARE(p->range(Dimension::X, 0).start(), 1); 1552 QCOMPARE(p->range(Dimension::X, 0).end(), 100); 1553 QCOMPARE(p->range(Dimension::Y, 0).start(), 1); 1554 QCOMPARE(p->range(Dimension::Y, 0).end(), 100); 1555 1556 auto children = project.children(AspectType::AbstractAspect, AbstractAspect::ChildIndexFlag::Recursive); 1557 1558 // Spreadsheet "Spreadsheet" 1559 // Column "1" 1560 // Column "2" 1561 // Column "3" 1562 // Column "4" 1563 // Worksheet "Worksheet" 1564 // CartesianPlot "Plot" 1565 // Axis "x" 1566 // Axis "x2" 1567 // Axis "y" 1568 // Axis "y2" 1569 // XYCurve "curve" 1570 // XYCurve "curve2" 1571 QCOMPARE(children.length(), 13); 1572 for (const auto& child : children) 1573 connect(child, &AbstractAspect::retransformCalledSignal, &c, &RetransformCallCounter::aspectRetransformed); 1574 1575 auto plots = project.children(AspectType::CartesianPlot, AbstractAspect::ChildIndexFlag::Recursive); 1576 QCOMPARE(plots.length(), 1); 1577 auto* plot = static_cast<CartesianPlot*>(plots[0]); 1578 connect(static_cast<CartesianPlot*>(plot), &CartesianPlot::scaleRetransformed, &c, &RetransformCallCounter::retransformScaleCalled); 1579 1580 // check axis ranges 1581 auto axes = project.children(AspectType::Axis, AbstractAspect::ChildIndexFlag::Recursive); 1582 QCOMPARE(axes.length(), 4); 1583 auto* xAxis1 = static_cast<Axis*>(axes.at(0)); 1584 auto* xAxis2 = static_cast<Axis*>(axes.at(1)); 1585 auto* yAxis1 = static_cast<Axis*>(axes.at(2)); 1586 auto* yAxis2 = static_cast<Axis*>(axes.at(3)); 1587 QCOMPARE(xAxis1->name(), QStringLiteral("x")); 1588 QCOMPARE(xAxis2->name(), QStringLiteral("x2")); 1589 QCOMPARE(yAxis1->name(), QStringLiteral("y")); 1590 QCOMPARE(yAxis2->name(), QStringLiteral("y2")); 1591 1592 auto list = QStringList({// data rect of the plot does not change, so retransforming the 1593 // plot is not needed 1594 QStringLiteral("Project/Worksheet/Plot/x"), 1595 QStringLiteral("Project/Worksheet/Plot/y"), 1596 QStringLiteral("Project/Worksheet/Plot/x2"), 1597 QStringLiteral("Project/Worksheet/Plot/y2"), 1598 QStringLiteral("Project/Worksheet/Plot/curve"), 1599 QStringLiteral("Project/Worksheet/Plot/curve2")}); 1600 1601 CartesianPlotDock dock(nullptr); 1602 dock.setPlots({plot}); 1603 dock.addYRange(); 1604 QCOMPARE(plot->rangeCount(Dimension::Y), 2); 1605 dock.addPlotRange(); 1606 QCOMPARE(plot->coordinateSystemCount(), 2); 1607 1608 c.resetRetransformCount(); 1609 1610 dock.PlotRangeChanged(1, Dimension::Y, 1); // switch for second csystem to y range 2 1611 1612 // No update of the scales, because the range did not change 1613 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1614 QCOMPARE(c.logsYScaleRetransformed.count(), 1); 1615 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 1); // The respective coordinate system must be rescaled 1616 1617 c.resetRetransformCount(); 1618 1619 XYCurveDock curveDock(nullptr); 1620 curveDock.setupGeneral(); 1621 curveDock.setCurves({curve}); 1622 QCOMPARE(curve->coordinateSystemIndex(), 0); 1623 curveDock.plotRangeChanged(1); // set curve range to other 1624 QCOMPARE(curve->coordinateSystemIndex(), 1); 1625 1626 // CSystem1: 1627 // x 1..100 1628 // y 1..30 1629 // CSystem2: 1630 // x 1..100 1631 // y 1..100 1632 1633 QCOMPARE(plot->range(Dimension::X, 0).start(), 1); 1634 QCOMPARE(plot->range(Dimension::X, 0).end(), 100); 1635 QCOMPARE(plot->range(Dimension::Y, 0).start(), 1); 1636 QCOMPARE(plot->range(Dimension::Y, 0).end(), 30); 1637 QCOMPARE(plot->range(Dimension::Y, 1).start(), 1); 1638 QCOMPARE(plot->range(Dimension::Y, 1).end(), 100); 1639 1640 // the y scale of cSystem1 and the y scale of CSystem2 shall be retransformed, because 1641 // cruve2 switches from y1 to y2 1642 // xScale shall not be retransformed because it did not change 1643 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1644 QCOMPARE(c.logsYScaleRetransformed.count(), 2); 1645 QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); 1646 QCOMPARE(c.logsYScaleRetransformed.at(1).index, 1); 1647 1648 const auto dataRect = plot->dataRect(); 1649 1650 // Check that both lines go from bottom to top 1651 { 1652 QCOMPARE(yAxis1->d_func()->lines.count(), 1); 1653 const auto line = yAxis1->d_func()->lines.at(0); 1654 QCOMPARE(line.p1().y(), dataRect.bottom()); 1655 QCOMPARE(line.p2().y(), dataRect.top()); 1656 } 1657 1658 { 1659 QCOMPARE(yAxis2->d_func()->lines.count(), 1); 1660 const auto line = yAxis2->d_func()->lines.at(0); 1661 QCOMPARE(line.p1().y(), dataRect.bottom()); 1662 QCOMPARE(line.p2().y(), dataRect.top()); 1663 } 1664 1665 // Now change cSystemIndex of second yAxis too 1666 c.resetRetransformCount(); 1667 1668 { 1669 AxisDock d(nullptr); 1670 d.setAxes({yAxis2}); 1671 d.plotRangeChanged(1); // change from cSystem1 to cSystem2 1672 } 1673 1674 // the y scale of cSystem1 and the y scale of CSystem2 shall be retransformed, because 1675 // yAxis2 switches from y1 to y2 1676 // xScale shall not be retransformed because it did not change 1677 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1678 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1679 // QCOMPARE(c.logsYScaleRetransformed.at(0).index, 0); // range did not change, so retransformScale gets not called 1680 // QCOMPARE(c.logsYScaleRetransformed.at(0).index, 1); // range did not change, so retransformScale gets not called 1681 1682 { 1683 QCOMPARE(yAxis1->d_func()->lines.count(), 1); 1684 const auto line = yAxis1->d_func()->lines.at(0); 1685 QCOMPARE(line.p1().y(), dataRect.bottom()); 1686 QCOMPARE(line.p2().y(), dataRect.top()); 1687 } 1688 1689 { 1690 QCOMPARE(yAxis2->d_func()->lines.count(), 1); 1691 const auto line = yAxis2->d_func()->lines.at(0); 1692 QCOMPARE(line.p1().y(), dataRect.bottom()); 1693 QCOMPARE(line.p2().y(), dataRect.top()); 1694 } 1695 } 1696 // ############################################################################## 1697 // ####### Tests checking the retransform behavior on plot shape changes ####### 1698 // ############################################################################## 1699 /*! 1700 * recalculation of plots without changing the min and max values of the data ranges. 1701 */ 1702 void RetransformTest::testPlotRecalcNoRetransform() { 1703 // prepare the data 1704 Spreadsheet sheet(QStringLiteral("test"), false); 1705 sheet.setColumnCount(1); 1706 sheet.setRowCount(100); 1707 auto* column = sheet.column(0); 1708 column->setValueAt(0, 2.); 1709 column->setValueAt(1, 4.); 1710 column->setValueAt(2, 6.); 1711 QVector<const AbstractColumn*> dataColumns; 1712 dataColumns << column; 1713 1714 // prepare the worksheet + plots 1715 RetransformCallCounter c; 1716 auto* ws = new Worksheet(QStringLiteral("worksheet")); 1717 auto* p = new CartesianPlot(QStringLiteral("plot")); 1718 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1719 ws->addChild(p); 1720 c.aspectAdded(p); 1721 const auto& axes = p->children<Axis>(); 1722 QCOMPARE(axes.count(), 2); 1723 c.aspectAdded(axes.at(0)); 1724 c.aspectAdded(axes.at(1)); 1725 1726 auto* barPlot = new BarPlot(QStringLiteral("barPlot")); 1727 barPlot->setDataColumns(dataColumns); 1728 p->addChild(barPlot); 1729 c.aspectAdded(barPlot); 1730 1731 auto* boxPlot = new BoxPlot(QStringLiteral("boxPlot")); 1732 boxPlot->setDataColumns(dataColumns); 1733 p->addChild(boxPlot); 1734 c.aspectAdded(boxPlot); 1735 1736 auto* histPlot = new Histogram(QStringLiteral("histPlot")); 1737 histPlot->setDataColumn(column); 1738 p->addChild(histPlot); 1739 c.aspectAdded(histPlot); 1740 1741 // call recalc() in the created plots which is called at runtime when modifying the data 1742 // or any plot properties affecting the shape of the plot. 1743 // since the data was not changed and no properties were changed affecting plot ranges 1744 // like the orientation of a box plot changing min and max values for x and y, etc., 1745 // there shouldn't be any retransform calls in the parent plot area 1746 c.resetRetransformCount(); 1747 barPlot->recalc(); 1748 { 1749 QCOMPARE(c.elementLogCount(false), 1); // only barplot 1750 const auto stat = c.statistic(false); 1751 QCOMPARE(stat.contains(barPlot->path()), true); 1752 QVERIFY(c.calledExact(1, false)); 1753 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1754 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1755 } 1756 1757 c.resetRetransformCount(); 1758 1759 boxPlot->recalc(); 1760 { 1761 QCOMPARE(c.elementLogCount(false), 1); // only boxPlot 1762 const auto stat = c.statistic(false); 1763 QCOMPARE(stat.contains(boxPlot->path()), true); 1764 QVERIFY(c.calledExact(1, false)); 1765 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1766 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1767 } 1768 1769 c.resetRetransformCount(); 1770 1771 histPlot->recalc(); 1772 1773 { 1774 QCOMPARE(c.elementLogCount(false), 1); // only histPlot 1775 const auto stat = c.statistic(false); 1776 QCOMPARE(stat.contains(histPlot->path()), true); 1777 QVERIFY(c.calledExact(1, false)); 1778 QCOMPARE(c.logsXScaleRetransformed.count(), 0); 1779 QCOMPARE(c.logsYScaleRetransformed.count(), 0); 1780 } 1781 } 1782 1783 /*! 1784 * recalculation of plots with changing the min and max values of the data ranges. 1785 */ 1786 void RetransformTest::testPlotRecalcRetransform() { 1787 // prepare the data 1788 Spreadsheet sheet(QStringLiteral("test"), false); 1789 sheet.setColumnCount(1); 1790 sheet.setRowCount(100); 1791 auto* column = sheet.column(0); 1792 column->setValueAt(0, 2.); 1793 column->setValueAt(1, 4.); 1794 column->setValueAt(2, 6.); 1795 QVector<const AbstractColumn*> dataColumns; 1796 dataColumns << column; 1797 1798 RetransformCallCounter c; 1799 1800 // prepare the worksheet + plots 1801 auto* ws = new Worksheet(QStringLiteral("worksheet")); 1802 auto* p = new CartesianPlot(QStringLiteral("plot")); 1803 p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created 1804 ws->addChild(p); 1805 c.aspectAdded(p); 1806 const auto& axes = p->children<Axis>(); 1807 QCOMPARE(axes.count(), 2); 1808 c.aspectAdded(axes.at(0)); 1809 c.aspectAdded(axes.at(1)); 1810 1811 auto* barPlot = new BarPlot(QStringLiteral("barPlot")); 1812 barPlot->setDataColumns(dataColumns); 1813 p->addChild(barPlot); 1814 c.aspectAdded(barPlot); 1815 1816 auto* boxPlot = new BoxPlot(QStringLiteral("boxPlot")); 1817 boxPlot->setDataColumns(dataColumns); 1818 p->addChild(boxPlot); 1819 c.aspectAdded(boxPlot); 1820 1821 auto* histPlot = new Histogram(QStringLiteral("histPlot")); 1822 histPlot->setDataColumn(column); 1823 p->addChild(histPlot); 1824 c.aspectAdded(histPlot); 1825 1826 c.resetRetransformCount(); 1827 1828 // modify one of the plots so its min and max values are changed. 1829 // this should trigger the recalculation of the data ranges in the parent plot area 1830 // and a retransform call for all its children 1831 QCOMPARE(histPlot->orientation(), Histogram::Orientation::Vertical); 1832 histPlot->setOrientation(Histogram::Orientation::Horizontal); 1833 1834 { 1835 const auto stat = c.statistic(false); 1836 QCOMPARE(stat.count(), 5); // barPlot, boxPlot, histPlot, xAxis and yAxis are inside 1837 QCOMPARE(stat.contains(barPlot->path()), true); 1838 QCOMPARE(stat.contains(boxPlot->path()), true); 1839 QCOMPARE(stat.contains(histPlot->path()), true); 1840 QCOMPARE(stat.contains(axes.at(0)->path()), true); 1841 QCOMPARE(stat.contains(axes.at(1)->path()), true); 1842 QVERIFY(c.calledExact(1, false)); 1843 QCOMPARE(c.logsXScaleRetransformed.count(), 1); 1844 QCOMPARE(c.logsYScaleRetransformed.count(), 0); // y range did not change, because boxplot and barplot are still vertical 1845 } 1846 1847 { 1848 c.resetRetransformCount(); 1849 QCOMPARE(barPlot->orientation(), BarPlot::Orientation::Vertical); 1850 barPlot->setOrientation(BarPlot::Orientation::Horizontal); 1851 const auto stat = c.statistic(false); 1852 QCOMPARE(stat.count(), 5); // barPlot, boxPlot, histPlot, xAxis and yAxis are inside 1853 QCOMPARE(stat.contains(barPlot->path()), true); 1854 QCOMPARE(stat.contains(boxPlot->path()), true); 1855 QCOMPARE(stat.contains(histPlot->path()), true); 1856 QCOMPARE(stat.contains(axes.at(0)->path()), true); 1857 QCOMPARE(stat.contains(axes.at(1)->path()), true); 1858 QVERIFY(c.calledExact(1, false)); 1859 QCOMPARE(c.logsXScaleRetransformed.count(), 1); 1860 QCOMPARE(c.logsYScaleRetransformed.count(), 0); // y range did not change, because boxplot is still vertical 1861 } 1862 1863 { 1864 c.resetRetransformCount(); 1865 QCOMPARE(boxPlot->orientation(), BoxPlot::Orientation::Vertical); 1866 boxPlot->setOrientation(BoxPlot::Orientation::Horizontal); 1867 1868 const auto stat = c.statistic(false); 1869 QCOMPARE(stat.count(), 5); // barPlot, boxPlot, histPlot, xAxis and yAxis are inside 1870 QCOMPARE(stat.contains(barPlot->path()), true); 1871 QCOMPARE(stat.contains(boxPlot->path()), true); 1872 QCOMPARE(stat.contains(histPlot->path()), true); 1873 QCOMPARE(stat.contains(axes.at(0)->path()), true); 1874 QCOMPARE(stat.contains(axes.at(1)->path()), true); 1875 QVERIFY(c.calledExact(1, false)); 1876 QCOMPARE(c.logsXScaleRetransformed.count(), 1); 1877 QCOMPARE(c.logsYScaleRetransformed.count(), 1); // y range changes 1878 } 1879 } 1880 1881 // ############################################################################################ 1882 // ############################################################################################ 1883 // ############################################################################################ 1884 1885 /*! 1886 * \brief RetransformCallCounter::statistic 1887 * Returns a statistic how often retransform was called for a specific element 1888 * They key is the path of the element and the value is the value how often 1889 * retransform was called 1890 * \param includeSuppressed. If true all retransforms even the suppressed once will 1891 * be counted. If false only the retransforms which are really executed are counted 1892 * \return 1893 */ 1894 QHash<QString, int> RetransformCallCounter::statistic(bool includeSuppressed) { 1895 QHash<QString, int> result; 1896 for (auto& log : logsRetransformed) { 1897 const auto& path = log.aspect->path(); 1898 if (!includeSuppressed && log.suppressed) 1899 continue; 1900 1901 if (!result.contains(path)) 1902 result.insert(path, 1); 1903 else 1904 result.insert(path, result.take(path) + 1); 1905 } 1906 return result; 1907 } 1908 1909 /*! 1910 * \brief RetransformCallCounter::elementLogCount 1911 * Counts the number of different elements which got at least one retransform 1912 * \param includeSuppressed 1913 * \return 1914 */ 1915 int RetransformCallCounter::elementLogCount(bool includeSuppressed) { 1916 return statistic(includeSuppressed).count(); 1917 } 1918 1919 /*! 1920 * \brief RetransformCallCounter::calledExact 1921 * Checks if all elements are retransformed \p requiredCallCount times 1922 * \param requiredCallCount 1923 * \param includeSuppressed 1924 * \return True if all elements are retransformed \p requiredCallCount times, else false 1925 */ 1926 bool RetransformCallCounter::calledExact(int requiredCallCount, bool includeSuppressed) { 1927 const auto& result = statistic(includeSuppressed); 1928 QHash<QString, int>::const_iterator i; 1929 for (i = result.constBegin(); i != result.constEnd(); ++i) { 1930 if (i.value() != requiredCallCount) { 1931 qDebug() << "Expected CallCount: " << requiredCallCount << ", Current: " << i.value() << ". " << i.key(); 1932 return false; 1933 } 1934 } 1935 return true; 1936 } 1937 1938 /*! 1939 * \brief RetransformCallCounter::callCount 1940 * Returns the call count of a specific element defined by \p path 1941 * \param path The path of the element element->path() 1942 * \return 1943 */ 1944 int RetransformCallCounter::callCount(const QString& path) { 1945 const auto& result = statistic(false); 1946 if (!result.contains(path)) 1947 return 0; 1948 1949 return result.value(path); 1950 } 1951 1952 /*! 1953 * \brief RetransformCallCounter::callCount 1954 * Returns the number of retransform called for a specific object. This counter contains 1955 * all retransforms from the beginning when the object was created and not yet connected 1956 * to the RetransformCallCounter object. This is usefull when checking the retransform 1957 * counts during loading of a project or during creation of an aspect 1958 * \param aspect 1959 * \return 1960 */ 1961 int RetransformCallCounter::callCount(const AbstractAspect* aspect) { 1962 return aspect->retransformCalled(); 1963 } 1964 1965 /*! 1966 * \brief RetransformCallCounter::resetRetransformCount 1967 * Reset all counters 1968 */ 1969 void RetransformCallCounter::resetRetransformCount() { 1970 logsRetransformed.clear(); 1971 logsXScaleRetransformed.clear(); 1972 logsYScaleRetransformed.clear(); 1973 } 1974 1975 /*! 1976 * \brief RetransformCallCounter::aspectRetransformed 1977 * Slot called whenever an aspects retransform was called after RetransformCallCounter::aspectAdded() 1978 * was called on the object. 1979 * \param sender 1980 * \param suppressed 1981 */ 1982 void RetransformCallCounter::aspectRetransformed(const AbstractAspect* sender, bool suppressed) { 1983 logsRetransformed.append({sender, suppressed}); 1984 } 1985 1986 /*! 1987 * \brief RetransformCallCounter::retransformScaleCalled 1988 * Slot called whenever an aspects retransformScale was called after RetransformCallCounter::aspectAdded() 1989 * was called on the object. 1990 * \param sender 1991 * \param suppressed 1992 */ 1993 void RetransformCallCounter::retransformScaleCalled(const CartesianPlot* plot, const Dimension dim, int index) { 1994 switch (dim) { 1995 case Dimension::X: 1996 logsXScaleRetransformed.append({plot, index}); 1997 break; 1998 case Dimension::Y: 1999 logsYScaleRetransformed.append({plot, index}); 2000 break; 2001 } 2002 } 2003 2004 /*! 2005 * \brief RetransformCallCounter::aspectAdded 2006 * Connect RetransformCallCounter to the aspects signals to count the retransform calls 2007 * \param aspect 2008 */ 2009 void RetransformCallCounter::aspectAdded(const AbstractAspect* aspect) { 2010 connect(aspect, &AbstractAspect::retransformCalledSignal, this, &RetransformCallCounter::aspectRetransformed); 2011 auto* plot = dynamic_cast<const CartesianPlot*>(aspect); 2012 if (plot) 2013 connect(plot, &CartesianPlot::scaleRetransformed, this, &RetransformCallCounter::retransformScaleCalled); 2014 } 2015 2016 // Test change data 2017 2018 QTEST_MAIN(RetransformTest)