File indexing completed on 2024-04-28 03:48:11

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 "XYCurveTest.h"
0012 
0013 #include "backend/worksheet/plots/cartesian/XYCurve.h"
0014 #include "backend/worksheet/plots/cartesian/XYCurvePrivate.h"
0015 
0016 #include "backend/core/Project.h"
0017 #include "backend/lib/trace.h"
0018 
0019 #include <QFile>
0020 
0021 #define GET_CURVE_PRIVATE(plot, child_index, column_name, curve_variable_name)                                                                                 \
0022     auto* curve_variable_name = plot->child<XYCurve>(child_index);                                                                                             \
0023     QVERIFY(curve_variable_name != nullptr);                                                                                                                   \
0024     QCOMPARE(curve_variable_name->name(), QLatin1String(column_name));                                                                                         \
0025     QCOMPARE(curve_variable_name->inherits(AspectType::XYCurve), true);                                                                                        \
0026     auto* curve_variable_name##Private = curve_variable_name->d_func();                                                                                        \
0027     Q_UNUSED(curve_variable_name##Private)
0028 
0029 #define LOAD_PROJECT                                                                                                                                           \
0030     Project project;                                                                                                                                           \
0031     project.load(QFINDTESTDATA(QLatin1String("data/TestUpdateLines.lml")));                                                                                    \
0032     auto* spreadsheet = project.child<AbstractAspect>(0);                                                                                                      \
0033     QVERIFY(spreadsheet != nullptr);                                                                                                                           \
0034     QCOMPARE(spreadsheet->name(), QLatin1String("lastValueInvalid"));                                                                                          \
0035     QCOMPARE(spreadsheet->type(), AspectType::Spreadsheet);                                                                                                    \
0036                                                                                                                                                                \
0037     auto* worksheet = project.child<AbstractAspect>(1);                                                                                                        \
0038     QVERIFY(worksheet != nullptr);                                                                                                                             \
0039     QCOMPARE(worksheet->name(), QLatin1String("Worksheet"));                                                                                                   \
0040     QCOMPARE(worksheet->type(), AspectType::Worksheet);                                                                                                        \
0041                                                                                                                                                                \
0042     auto* plot = worksheet->child<CartesianPlot>(0);                                                                                                           \
0043     QVERIFY(plot != nullptr);                                                                                                                                  \
0044     QCOMPARE(plot->name(), QLatin1String("plot"));                                                                                                             \
0045     /* enable once implemented correctly */                                                                                                                    \
0046     /* QCOMPARE(plot->type(), AspectType::CartesianPlot); */                                                                                                   \
0047                                                                                                                                                                \
0048     GET_CURVE_PRIVATE(plot, 0, "lastValueInvalid", lastValueInvalidCurve)                                                                                      \
0049     GET_CURVE_PRIVATE(plot, 1, "lastVertical", lastVerticalCurve)                                                                                              \
0050     GET_CURVE_PRIVATE(plot, 2, "withGap", withGapCurve)                                                                                                        \
0051     GET_CURVE_PRIVATE(plot, 3, "withGap2", withGapCurve2)                                                                                                      \
0052                                                                                                                                                                \
0053     auto* nonlinearWorksheet = project.child<AbstractAspect>(4);                                                                                               \
0054     QVERIFY(nonlinearWorksheet != nullptr);                                                                                                                    \
0055     QCOMPARE(nonlinearWorksheet->name(), QLatin1String("Nonlinear"));                                                                                          \
0056     QCOMPARE(nonlinearWorksheet->type(), AspectType::Worksheet);                                                                                               \
0057                                                                                                                                                                \
0058     auto* nonlinearPlot = nonlinearWorksheet->child<CartesianPlot>(0);                                                                                         \
0059     QVERIFY(nonlinearPlot != nullptr);                                                                                                                         \
0060     QCOMPARE(nonlinearPlot->name(), QLatin1String("xy-plot"));                                                                                                 \
0061     GET_CURVE_PRIVATE(nonlinearPlot, 0, "f(x)=x", linear)
0062 
0063 #define LOAD_HOVER_PROJECT                                                                                                                                     \
0064     Project project;                                                                                                                                           \
0065     project.load(QFINDTESTDATA(QLatin1String("data/curveHover.lml")));                                                                                         \
0066     auto* spreadsheet = project.child<AbstractAspect>(0);                                                                                                      \
0067     QVERIFY(spreadsheet != nullptr);                                                                                                                           \
0068     QCOMPARE(spreadsheet->name(), QLatin1String("Spreadsheet"));                                                                                               \
0069     QCOMPARE(spreadsheet->type(), AspectType::Spreadsheet);                                                                                                    \
0070                                                                                                                                                                \
0071     auto* worksheet = project.child<AbstractAspect>(1);                                                                                                        \
0072     QVERIFY(worksheet != nullptr);                                                                                                                             \
0073     QCOMPARE(worksheet->name(), QLatin1String("Worksheet - Spreadsheet"));                                                                                     \
0074     QCOMPARE(worksheet->type(), AspectType::Worksheet);                                                                                                        \
0075                                                                                                                                                                \
0076     auto* plot = worksheet->child<CartesianPlot>(0);                                                                                                           \
0077     QVERIFY(plot != nullptr);                                                                                                                                  \
0078     QCOMPARE(plot->name(), QLatin1String("Plot - Spreadsheet"));                                                                                               \
0079     /* enable once implemented correctly */                                                                                                                    \
0080     /* QCOMPARE(plot->type(), AspectType::CartesianPlot); */                                                                                                   \
0081                                                                                                                                                                \
0082     GET_CURVE_PRIVATE(plot, 0, "IntegerNonMonotonic", integerNonMonotonic)
0083 
0084 #define COMPARE_LINES(line1, line2) QVERIFY((line1.p1() == line2.p1() && line1.p2() == line2.p2()) || (line1.p1() == line2.p2() && line1.p2() == line2.p1()))
0085 
0086 void addUniqueLine01(QPointF p, double& minY, double& maxY, QPointF& lastPoint, int& pixelDiff, QVector<QLineF>& lines, bool& prevPixelDiffZero);
0087 void addUniqueLine02(QPointF p, double& minY, double& maxY, QPointF& lastPoint, int& pixelDiff, QVector<QLineF>& lines, bool& prevPixelDiffZero);
0088 void addUniqueLine_double_vector(double* p, double& minY, double& maxY, QPointF& lastPoint, int& pixelDiff, QVector<QLineF>& lines, bool& prevPixelDiffZero);
0089 void addUniqueLine_double_vector_last_point_vector(double* p,
0090                                                    double& minY,
0091                                                    double& maxY,
0092                                                    double* lastPoint,
0093                                                    int& pixelDiff,
0094                                                    QVector<QLineF>& lines,
0095                                                    bool& prevPixelDiffZero);
0096 void addUniqueLine_double_vector_last_point_vector_lines_vector(double* p,
0097                                                                 double& minY,
0098                                                                 double& maxY,
0099                                                                 double* lastPoint,
0100                                                                 int& pixelDiff,
0101                                                                 double* lines,
0102                                                                 bool& prevPixelDiffZero,
0103                                                                 int& numberLines);
0104 void addUniqueLine_double_vector_last_point_vector_lines_vector_add4(double* p,
0105                                                                      double& minY,
0106                                                                      double& maxY,
0107                                                                      double* lastPoint,
0108                                                                      int& pixelDiff,
0109                                                                      double* lines,
0110                                                                      bool& prevPixelDiffZero,
0111                                                                      int& numberLines);
0112 void addUniqueLine_double_vector_last_point_vector_lines_vector_add4_dont_copy_last_point(double* p,
0113                                                                                           double& minY,
0114                                                                                           double& maxY,
0115                                                                                           double** lastPoint,
0116                                                                                           int& pixelDiff,
0117                                                                                           double* lines,
0118                                                                                           bool& prevPixelDiffZero,
0119                                                                                           int& numberLines);
0120 
0121 #define doublesToString(v1, v2, v3, v4) QString::number(v1) + "," + QString::number(v2) + "," + QString::number(v3) + "," + QString::number(v4)
0122 #define lineToString(line) doublesToString(line.p1().x(), line.p1().y(), line.p2().x(), line.p2().y())
0123 
0124 void XYCurveTest::addUniqueLineTest01() {
0125     //  // For performance Testing only
0126 
0127     //  /*
0128     //   * Summary:
0129     //   * - Using .at() is faster than []
0130     //   * - Chaching calculations. So (std::round(x / minLogicalDiffX)) must not be
0131     //   * done every time.
0132     //   * - Try to get as much as possible calculations away. instead of abs() use !=
0133     //   * 0 which is secure for long int
0134     //   */
0135     //  const int count = 100e6;
0136     //  const double maxValue = 100;
0137     //  const int numberPixel = 680;
0138     //  const double minLogicalDiffX = maxValue / numberPixel; // amount pixel = count/minLogicalDiffX
0139     //  const int maximumLines = 2 * numberPixel; // number Pixel horizontal lines, number Pixel vertical lines
0140 
0141     //  //  {
0142     //  //      QVector<QLineF> lines;
0143     //  //      bool prevPixelDiffZero = false;
0144     //  //      x = 0;
0145     //  //      PERFTRACE(QString(Q_FUNC_INFO) + "XYCurve::addUniqueLine use array
0146     //  // access");        for (int i=0; i < count; i++) {             pixelDiff =
0147     //  // llabs(std::round(points[i].x() / minLogicalDiffX) - std::round(x /
0148     //  // minLogicalDiffX)) > 0; // only relevant if greater zero or not
0149     //  //          XYCurvePrivate::addUniqueLine(points[i], minY, maxY, lastPoint,
0150     //  // pixelDiff, lines, prevPixelDiffZero);            if (pixelDiff > 0) // set x to next
0151     //  // pixel                x += minLogicalDiffX;
0152     //  //      }
0153     //  //  }
0154 
0155     //  {
0156     //      double x = 0;
0157     //      double minY = INFINITY;
0158     //      double maxY = -INFINITY;
0159     //      QPointF lastPoint;
0160     //      int pixelDiff = 0;
0161     //      QVector<QPointF> points(count);
0162     //      for (int i = 0; i < count; i++) {
0163     //          points[i].setX(double(i) / count * maxValue);
0164     //          points[i].setY(sin(double(i) / count * 2. * 3.1416 * 20.));
0165     //      }
0166     //      QVector<QLineF> lines;
0167     //      {
0168     //          bool prevPixelDiffZero = false;
0169     //          x = 0;
0170     //          PERFTRACE(QString(Q_FUNC_INFO) + "01_XYCurve::addUniqueLine use @access");
0171     //          for (int i = 0; i < count; i++) {
0172     //              pixelDiff = llabs(std::round(points.at(i).x() / minLogicalDiffX) - std::round(x / minLogicalDiffX)) > 0; // only relevant if greater zero or
0173     // not              XYCurvePrivate::addUniqueLine(points.at(i), minY, maxY, lastPoint, pixelDiff, lines, prevPixelDiffZero);
0174     //              if (pixelDiff > 0) // set x to next pixel
0175     //                  x += minLogicalDiffX;
0176     //          }
0177     //      }
0178     //      qDebug() << x;
0179     //      QFile f("01_addUniqueLine_use_at_access.txt");
0180     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0181     //      for (auto& line : lines) {
0182     //          QTextStream out(&f);
0183     //          out << lineToString(line) << "\n";
0184     //      }
0185     //      f.close();
0186     //  }
0187 
0188     //  {
0189     //      double x = 0;
0190     //      double minY = INFINITY;
0191     //      double maxY = -INFINITY;
0192     //      QPointF lastPoint;
0193     //      int pixelDiff = 0;
0194     //      QVector<QPointF> points(count);
0195     //      for (int i = 0; i < count; i++) {
0196     //          points[i].setX(double(i) / count * maxValue);
0197     //          points[i].setY(sin(double(i) / count * 2. * 3.1416 * 20.));
0198     //      }
0199     //      QVector<QLineF> lines;
0200     //      {
0201     //          qint64 r = 0;
0202     //          bool prevPixelDiffZero = false;
0203     //          x = 0;
0204     //          PERFTRACE(QString(Q_FUNC_INFO) +
0205     //                "011_XYCurve::addUniqueLine use @access try to simplify "
0206     //                "calculation, cache x/minLogicalDiffX");
0207     //          for (int i = 0; i < count; i++) {
0208     //              pixelDiff = (std::round(points.at(i).x() / minLogicalDiffX) - r) != 0; // only relevant if greater zero or not
0209     //              XYCurvePrivate::addUniqueLine(points.at(i), minY, maxY, lastPoint, pixelDiff, lines, prevPixelDiffZero);
0210     //              if (pixelDiff > 0) { // set x to next pixel
0211     //                  x += minLogicalDiffX;
0212     //                  r = std::round(x / minLogicalDiffX);
0213     //              }
0214     //          }
0215     //      }
0216     //      qDebug() << x;
0217     //      QFile f("011_addUniqueLine_use_at_access.txt");
0218     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0219     //      for (auto& line : lines) {
0220     //          QTextStream out(&f);
0221     //          out << lineToString(line) << "\n";
0222     //      }
0223     //      f.close();
0224     //  }
0225 
0226     //  //{
0227     //  //  double x = 0;
0228     //  //  double minY = INFINITY;
0229     //  //  double maxY = -INFINITY;
0230     //  //  QPointF lastPoint;
0231     //  //  int pixelDiff = 0;
0232     //  //  QVector<QPointF> points(count);
0233     //  //  for (int i = 0; i < count; i++) {
0234     //  //      points[i].setX(double(i)/count * maxValue);
0235     //  //      points[i].setY(sin(double(i)/count * 2. * 3.1416 * 20.));
0236     //  //  }
0237     //  //  QVector<qint64> pixelDiff_;
0238 
0239     //  //  // just to export pixelDiff
0240     //  //  QVector<QLineF> lines;
0241     //  //  {
0242     //  //      bool prevPixelDiffZero = false;
0243     //  //      x = 0;
0244     //  //      for (int i=0; i < count; i++) {
0245     //  //          qint64 res = llabs(std::round(points.at(i).x() / minLogicalDiffX)
0246     //  //- std::round(x / minLogicalDiffX));           pixelDiff_.append(res);             pixelDiff = res >
0247     //  // 0; // only relevant if greater zero or not
0248     //  //          XYCurvePrivate::addUniqueLine(points.at(i), minY, maxY,
0249     //  // lastPoint, pixelDiff, lines, prevPixelDiffZero);             if (pixelDiff > 0) // set x
0250     //  // to next pixel                x += minLogicalDiffX;
0251     //  //      }
0252     //  //  }
0253     //  //  qDebug() << x;
0254     //  //  QFile f("PixelDiff.txt");
0255     //  //  f.open(QIODevice::OpenModeFlag::WriteOnly);
0256     //  //  for (auto& pd: pixelDiff_) {
0257     //  //      QTextStream out(&f);
0258     //  //      out << pd << "\n";
0259     //  //  }
0260     //  //  f.close();
0261     //  //}
0262 
0263     //  {
0264     //      double x = 0;
0265     //      double minY = INFINITY;
0266     //      double maxY = -INFINITY;
0267     //      QPointF lastPoint;
0268     //      int pixelDiff = 0;
0269     //      QPointF* pointerArray = (QPointF*)malloc(count * sizeof(QPointF));
0270     //      for (int i = 0; i < count; i++) {
0271     //          pointerArray[i].setX(double(i) / count * maxValue);
0272     //          pointerArray[i].setY(sin(double(i) / count * 2. * 3.1416 * 20.));
0273     //      }
0274     //      QVector<QLineF> lines;
0275     //      {
0276     //          bool prevPixelDiffZero = false;
0277     //          x = 0;
0278     //          PERFTRACE(QString(Q_FUNC_INFO) + "02_XYCurve::addUniqueLine use raw vector");
0279     //          for (int i = 0; i < count; i++) {
0280     // only relevant if greater zero or not
0281     //              pixelDiff = llabs(std::round(pointerArray[i].x() / minLogicalDiffX) - std::round(x / minLogicalDiffX)) > 0;
0282     //          addUniqueLine01(pointerArray[i], minY, maxY, lastPoint, pixelDiff, lines, prevPixelDiffZero);
0283     //          if (pixelDiff > 0) // set x to next pixel
0284     //             x += minLogicalDiffX;
0285     //          }
0286     //      }
0287     //      qDebug() << x;
0288     //      QFile f("02_addUniqueLine_use_raw_vector.txt");
0289     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0290     //      for (auto& line : lines) {
0291     //          QTextStream out(&f);
0292     //          out << lineToString(line) << "\n";
0293     //      }
0294     //      f.close();
0295     //      free(pointerArray);
0296     //  }
0297 
0298     //  {
0299     //      double x = 0;
0300     //      double minY = INFINITY;
0301     //      double maxY = -INFINITY;
0302     //      QPointF lastPoint;
0303     //      int pixelDiff = 0;
0304     //      double* pointerArray = (double*)malloc(count * 2 * sizeof(double));
0305     //      for (int i = 0; i < count; i++) {
0306     //          pointerArray[2 * i] = double(i) / count * maxValue;
0307     //          pointerArray[2 * i + 1] = sin(double(i) / count * 2. * 3.1416 * 20.);
0308     //      }
0309     //      QVector<QLineF> lines;
0310     //      {
0311     //          bool prevPixelDiffZero = false;
0312     //          PERFTRACE(QString(Q_FUNC_INFO) + "03_XYCurve::addUniqueLine use raw double vector");
0313     //          for (int i = 0; i < count; i++) {
0314     //              only relevant if greater zero or not
0315     //              pixelDiff = llabs(std::round(pointerArray[2 * i] / minLogicalDiffX) - std::round(x / minLogicalDiffX)) > 0;
0316     //              addUniqueLine_double_vector(&pointerArray[2 * i], minY, maxY, lastPoint, pixelDiff, lines, prevPixelDiffZero);
0317     //              if (pixelDiff > 0) // set x to next pixel
0318     //                  x += minLogicalDiffX;
0319     //          }
0320     //      }
0321     //      qDebug() << x;
0322     //      QFile f("03_addUniqueLine_use_raw_double_vector.txt");
0323     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0324     //      for (auto& line : lines) {
0325     //          QTextStream out(&f);
0326     //          out << lineToString(line) << "\n";
0327     //      }
0328     //      f.close();
0329     //      free(pointerArray);
0330     //  }
0331 
0332     //  {
0333     //      double x = 0;
0334     //      double minY = INFINITY;
0335     //      double maxY = -INFINITY;
0336     //      int pixelDiff = 0;
0337     //      double* pointerArray = (double*)malloc(count * 2 * sizeof(double));
0338     //      double lastPoint[2] = {0};
0339     //      for (int i = 0; i < count; i++) {
0340     //          pointerArray[2 * i] = double(i) / count * maxValue;
0341     //          pointerArray[2 * i + 1] = sin(double(i) / count * 2. * 3.1416 * 20.);
0342     //      }
0343     //      QVector<QLineF> lines;
0344     //      {
0345     //          bool prevPixelDiffZero = false;
0346     //          PERFTRACE(QString(Q_FUNC_INFO) +
0347     //                "04_XYCurve::addUniqueLine use raw double vector last point "
0348     //                "double vector");
0349     //          for (int i = 0; i < count; i++) {
0350     //              pixelDiff = llabs(std::round(pointerArray[2 * i] / minLogicalDiffX) - std::round(x / minLogicalDiffX)) > 0; // only relevant if greater zero
0351     // or
0352     // not              addUniqueLine_double_vector_last_point_vector(&pointerArray[2 * i], minY, maxY, lastPoint, pixelDiff, lines, prevPixelDiffZero);
0353     // if (pixelDiff > 0) // set x to next pixel                    x += minLogicalDiffX;
0354     //          }
0355     //      }
0356     //      qDebug() << x;
0357     //      QFile f("04_addUniqueLine_use_raw_double_vector_last_point_double_vector.txt");
0358     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0359     //      for (auto& line : lines) {
0360     //          QTextStream out(&f);
0361     //          out << lineToString(line) << "\n";
0362     //      }
0363     //      f.close();
0364     //      free(pointerArray);
0365     //  }
0366 
0367     //  {
0368     //      double x = 0;
0369     //      double minY = INFINITY;
0370     //      double maxY = -INFINITY;
0371     //      int pixelDiff = 0;
0372     //      double* pointerArray = (double*)malloc(count * 2 * sizeof(double));
0373     //      double lastPoint[2] = {0};
0374     //      for (int i = 0; i < count; i++) {
0375     //          pointerArray[2 * i] = double(i) / count * maxValue;
0376     //          pointerArray[2 * i + 1] = sin(double(i) / count * 2. * 3.1416 * 20.);
0377     //      }
0378     //      QVector<QLineF> lines2;
0379     //      {
0380     //          bool prevPixelDiffZero = false;
0381     //          int number_lines = 0;
0382     //          double* lines = (double*)malloc(maximumLines * 4 * sizeof(double));
0383     //          PERFTRACE(QString(Q_FUNC_INFO) +
0384     //                "05_XYCurve::addUniqueLine use raw double vector "
0385     //                "last_point_double lines_double_vector");
0386     //          for (int i = 0; i < count; i++) {
0387     //              pixelDiff = llabs(std::round(pointerArray[2 * i] / minLogicalDiffX) - std::round(x / minLogicalDiffX)) > 0; // only relevant if greater zero
0388     // or
0389     // not              addUniqueLine_double_vector_last_point_vector_lines_vector(&pointerArray[2 * i],
0390     // minY, maxY, lastPoint,                                                                          pixelDiff, lines, prevPixelDiffZero,
0391     // number_lines);               if (pixelDiff > 0) // set x to next pixel                   x += minLogicalDiffX;
0392     //          }
0393 
0394     //          for (int i = 0; i < number_lines; i++)
0395     //              lines2.append(QLineF(lines[i * 4], lines[i * 4 + 1], lines[i * 4 + 2], lines[i * 4 + 3]));
0396     //          free(lines);
0397     //      }
0398     //      qDebug() << x;
0399     //      QFile f(
0400     //          "05_addUniqueLine_use_raw_double_vector_last_point_double_vector_"
0401     //          "lines_double_vector.txt");
0402     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0403     //      for (auto& line : lines2) {
0404     //          QTextStream out(&f);
0405     //          out << lineToString(line) << "\n";
0406     //      }
0407     //      f.close();
0408     //      free(pointerArray);
0409     //  }
0410 
0411     //  {
0412     //      double x = 0;
0413     //      double minY = INFINITY;
0414     //      double maxY = -INFINITY;
0415     //      int pixelDiff = 0;
0416     //      double* pointerArray = (double*)malloc(count * 2 * sizeof(double));
0417     //      double lastPoint[2] = {0};
0418     //      for (int i = 0; i < count; i++) {
0419     //          pointerArray[2 * i] = double(i) / count * maxValue;
0420     //          pointerArray[2 * i + 1] = sin(double(i) / count * 2. * 3.1416 * 20.);
0421     //      }
0422     //      qint64 r = 0;
0423     //      QVector<QLineF> lines2;
0424     //      {
0425     //          bool prevPixelDiffZero = false;
0426     //          int number_lines = 0;
0427     //          double* lines = (double*)malloc(maximumLines * 4 * sizeof(double));
0428     //          PERFTRACE(QString(Q_FUNC_INFO) + "051_XYCurve::addUniqueLine use raw "
0429     //                                       "double vector cache x/minLogicalDiffX");
0430     //          for (int i = 0; i < count; i++) {
0431     //              pixelDiff = llabs(std::round(pointerArray[2 * i] / minLogicalDiffX) - r) > 0; // only relevant if greater zero or not
0432     //              addUniqueLine_double_vector_last_point_vector_lines_vector(&pointerArray[2 * i],
0433     //                                                                         minY,
0434     //                                                                         maxY,
0435     //                                                                         lastPoint,
0436     //                                                                         pixelDiff,
0437     //                                                                         lines,
0438     //                                                                         prevPixelDiffZero,
0439     //                                                                         number_lines);
0440     //              if (pixelDiff > 0) { // set x to next pixel
0441     //                  x += minLogicalDiffX;
0442     //                  r = std::round(x / minLogicalDiffX);
0443     //              }
0444     //          }
0445 
0446     //          for (int i = 0; i < number_lines; i++)
0447     //              lines2.append(QLineF(lines[i * 4], lines[i * 4 + 1], lines[i * 4 + 2], lines[i * 4 + 3]));
0448     //          free(lines);
0449     //      }
0450     //      qDebug() << x;
0451     //      QFile f(
0452     //          "051_addUniqueLine_use_raw_double_vector_last_point_double_vector_"
0453     //          "lines_double_vector_cache_x_minLogicalDiffX.txt");
0454     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0455     //      for (auto& line : lines2) {
0456     //          QTextStream out(&f);
0457     //          out << lineToString(line) << "\n";
0458     //      }
0459     //      f.close();
0460     //      free(pointerArray);
0461     //  }
0462 
0463     //  {
0464     //      double x = 0;
0465     //      double minY = INFINITY;
0466     //      double maxY = -INFINITY;
0467     //      int pixelDiff = 0;
0468     //      double* pointerArray = (double*)malloc(count * 2 * sizeof(double));
0469     //      double lastPoint[2] = {0};
0470     //      for (int i = 0; i < count; i++) {
0471     //          pointerArray[2 * i] = double(i) / count * maxValue;
0472     //          pointerArray[2 * i + 1] = sin(double(i) / count * 2. * 3.1416 * 20.);
0473     //      }
0474     //      qint64 r = 0;
0475     //      QVector<QLineF> lines2;
0476     //      {
0477     //          bool prevPixelDiffZero = false;
0478     //          int number_lines = 0;
0479     //          double* lines = (double*)malloc(maximumLines * 4 * sizeof(double));
0480     //          PERFTRACE(QString(Q_FUNC_INFO) +
0481     //                "0511_XYCurve::addUniqueLine use raw double vector cache "
0482     //                "x/minLogicalDiffX remove abs");
0483     //          for (int i = 0; i < count; i++) {
0484     //              pixelDiff = (std::round(pointerArray[2 * i] / minLogicalDiffX) - r) != 0; // only relevant if not zero
0485     //              addUniqueLine_double_vector_last_point_vector_lines_vector(&pointerArray[2 * i],
0486     //                                                                         minY,
0487     //                                                                         maxY,
0488     //                                                                         lastPoint,
0489     //                                                                         pixelDiff,
0490     //                                                                         lines,
0491     //                                                                         prevPixelDiffZero,
0492     //                                                                         number_lines);
0493     //              if (pixelDiff > 0) { // set x to next pixel
0494     //                  x += minLogicalDiffX;
0495     //                  r = std::round(x / minLogicalDiffX);
0496     //              }
0497     //          }
0498 
0499     //          for (int i = 0; i < number_lines; i++)
0500     //              lines2.append(QLineF(lines[i * 4], lines[i * 4 + 1], lines[i * 4 + 2], lines[i * 4 + 3]));
0501     //          free(lines);
0502     //      }
0503     //      qDebug() << x;
0504     //      QFile f(
0505     //          "0511_addUniqueLine_use_raw_double_vector_last_point_double_vector_"
0506     //          "lines_double_vector_cache_x_minLogicalDiffX.txt");
0507     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0508     //      for (auto& line : lines2) {
0509     //          QTextStream out(&f);
0510     //          out << lineToString(line) << "\n";
0511     //      }
0512     //      f.close();
0513     //      free(pointerArray);
0514     //  }
0515 
0516     //  //  {
0517     //  //      double x = 0;
0518     //  //      double minY = INFINITY;
0519     //  //      double maxY = -INFINITY;
0520     //  //      int pixelDiff = 0;
0521     //  //      double* pointerArray = (double*)malloc(count * 2 *
0522     //  // sizeof(double));         double lastPoint[2] = {0};      for (int i = 0; i < count; i++)
0523     //  //{             pointerArray[2*i] = double(i)/count * maxValue;             pointerArray[2*i + 1] =
0524     //  // sin(double(i)/count * 2. * 3.1416 * 20.);
0525     //  //      }
0526     //  //      qint64 r = 0;
0527     //  //      int number_lines = 0;
0528     //  //      double* lines = (double*)malloc(maximumLines * 4 *
0529     //  // sizeof(double));
0530     //  //      {
0531     //  //          bool prevPixelDiffZero = false;
0532     //  //          PERFTRACE(QString(Q_FUNC_INFO) + "052_XYCurve::addUniqueLine use
0533     //  // raw double vector cache x/minLogicalDiffX without linecopy");            for (int i=0;
0534     //  // i < count; i++) {                pixelDiff = llabs(std::round(pointerArray[2*i] /
0535     //  // minLogicalDiffX) - r) > 0; // only relevant if greater zero or not
0536     //  //              addUniqueLine_double_vector_last_point_vector_lines_vector(&pointerArray[2*i],
0537     //  // minY, maxY, lastPoint, pixelDiff, lines, prevPixelDiffZero, number_lines);
0538     //  //              if (pixelDiff > 0) { // set x to next pixel
0539     //  //                  x += minLogicalDiffX;
0540     //  //                  r = std::round(x / minLogicalDiffX);
0541     //  //              }
0542     //  //          }
0543     //  //      }
0544     //  //      qDebug() << x;
0545     //  //      QFile
0546     //  // f("052_addUniqueLine_use_raw_double_vector_last_point_double_vector_lines_double_vector_cache_x_minLogicalDiffX_without_line_copy.txt");
0547     //  //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0548     //  //      for (int i=0; i < number_lines; i++) {
0549     //  //          QTextStream out(&f);
0550     //  //          out << doublesToString(lines[i*4], lines[i*4 + 1], lines[i*4 +
0551     //  // 2], lines[i*4 + 3]) << "\n";
0552     //  //      }
0553     //  //      f.close();
0554     //  //      free(lines);
0555     //  //      free(pointerArray);
0556     //  //  }
0557 
0558     //  {
0559     //      double x = 0;
0560     //      double minY = INFINITY;
0561     //      double maxY = -INFINITY;
0562     //      int pixelDiff = 0;
0563     //      double* pointerArray = (double*)malloc(count * 2 * sizeof(double));
0564     //      double lastPoint[2] = {0};
0565     //      for (int i = 0; i < count; i++) {
0566     //          pointerArray[2 * i] = double(i) / count * maxValue;
0567     //          pointerArray[2 * i + 1] = sin(double(i) / count * 2. * 3.1416 * 20.);
0568     //      }
0569     //      qint64 r = 0;
0570     //      int number_lines = 0;
0571     //      double* lines = (double*)malloc(maximumLines * 4 * sizeof(double));
0572     //      {
0573     //          bool prevPixelDiffZero = false;
0574     //          PERFTRACE(
0575     //          QString(Q_FUNC_INFO) +
0576     //          "053_XYCurve::addUniqueLine use raw double vector cache "
0577     //          "x/minLogicalDiffX without linecopy number_lines add 4 directly");
0578     //          for (int i = 0; i < count; i++) {
0579     //              pixelDiff = llabs(std::round(pointerArray[2 * i] / minLogicalDiffX) - r) > 0; // only relevant if greater zero or not
0580     //              addUniqueLine_double_vector_last_point_vector_lines_vector_add4(&pointerArray[2 * i],
0581     //                                                                              minY,
0582     //                                                                              maxY,
0583     //                                                                              lastPoint,
0584     //                                                                              pixelDiff,
0585     //                                                                              lines,
0586     //                                                                              prevPixelDiffZero,
0587     //                                                                              number_lines);
0588     //              if (pixelDiff > 0) { // set x to next pixel
0589     //                  x += minLogicalDiffX;
0590     //                  r = std::round(x / minLogicalDiffX);
0591     //              }
0592     //          }
0593     //      }
0594     //      qDebug() << x;
0595     //      QFile f("053.txt");
0596     //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0597     //      for (int i = 0; i < number_lines; i++) {
0598     //          QTextStream out(&f);
0599     //          out << doublesToString(lines[i * 4], lines[i * 4 + 1], lines[i * 4 + 2], lines[i * 4 + 3]) << "\n";
0600     //      }
0601     //      f.close();
0602     //      free(lines);
0603     //      free(pointerArray);
0604     //  }
0605 
0606     //  //  // Does not work. Get segmentation fault
0607     //  //  {
0608     //  //      double x = 0;
0609     //  //      double minY = INFINITY;
0610     //  //      double maxY = -INFINITY;
0611     //  //      int pixelDiff = 0;
0612     //  //      double* pointerArray = (double*)malloc(count * 2 *
0613     //  // sizeof(double));         double *lastPoint = nullptr;        for (int i = 0; i < count;
0614     //  // i++) {           pointerArray[2*i] = double(i)/count * maxValue;             pointerArray[2*i + 1]
0615     //  //= sin(double(i)/count * 2. * 3.1416 * 20.);
0616     //  //      }
0617     //  //      qint64 r = 0;
0618     //  //      int number_lines = 0;
0619     //  //      double* lines = (double*)malloc(maximumLines * 4 *
0620     //  // sizeof(double));
0621     //  //      {
0622     //  //          bool prevPixelDiffZero = false;
0623     //  //          PERFTRACE(QString(Q_FUNC_INFO) + "06_XYCurve::addUniqueLine use
0624     //  // raw double vector cache x/minLogicalDiffX without linecopy number_lines add
0625     //  // 4 directly don't copy last point");          for (int i=0; i < count; i++) {
0626     //  //              pixelDiff = llabs(std::round(pointerArray[2*i] /
0627     //  // minLogicalDiffX) - r) > 0; // only relevant if greater zero or not
0628     //  //              addUniqueLine_double_vector_last_point_vector_lines_vector_add4_dont_copy_last_point(&pointerArray[2*i],
0629     //  // minY, maxY, &lastPoint, pixelDiff, lines, prevPixelDiffZero, number_lines);
0630     //  //              if (pixelDiff > 0) { // set x to next pixel
0631     //  //                  x += minLogicalDiffX;
0632     //  //                  r = std::round(x / minLogicalDiffX);
0633     //  //              }
0634     //  //          }
0635     //  //      }
0636     //  //      qDebug() << x;
0637     //  //      QFile f("06.txt");
0638     //  //      f.open(QIODevice::OpenModeFlag::WriteOnly);
0639     //  //      for (int i=0; i < number_lines; i++) {
0640     //  //          QTextStream out(&f);
0641     //  //          out << doublesToString(lines[i*4], lines[i*4 + 1], lines[i*4 +
0642     //  // 2], lines[i*4 + 3]) << "\n";
0643     //  //      }
0644     //  //      f.close();
0645     //  //      free(lines);
0646     //  //      free(pointerArray);
0647     //  //  }
0648 
0649     //  //  {
0650     //  //      QVector<QLineF> lines;
0651     //  //      PERFTRACE(QString(Q_FUNC_INFO) + "Add to line");
0652     //  //      for (int i=0; i < maximumLines; i++) {
0653     //  //          lines.append(QLineF(points.at(i), points.at(i+1)));
0654     //  //      }
0655     //  //      (void)lines;
0656     //  //  }
0657 
0658     //  //  {
0659     //  //      QVector<QLineF> lines;
0660     //  //      bool prevPixelDiffZero = false;
0661     //  //      // Reallocating array
0662     //  //      x = 0;
0663     //  //      lines.resize(maximumLines);
0664     //  //  PERFTRACE(QString(Q_FUNC_INFO) + "addUniqueLine PreAllocate");
0665     //  //      for (int i=0; i < count; i++) {
0666     //  //          pixelDiff = llabs(std::round(points.at(i).x() / minLogicalDiffX) -
0667     //  // std::round(x / minLogicalDiffX)) > 0; // only relevant if greater zero or not
0668     //  //          XYCurvePrivate::addUniqueLine(points.at(i), minY, maxY,
0669     //  // lastPoint, pixelDiff, lines, prevPixelDiffZero);             if (pixelDiff > 0) // set x
0670     //  // to next pixel                x += minLogicalDiffX;
0671     //  //      }
0672     //  //  }
0673 }
0674 
0675 void addUniqueLine01(QPointF p, double& minY, double& maxY, QPointF& lastPoint, const int& pixelDiff, QVector<QLineF>& lines, bool& prevPixelDiffZero) {
0676     if (pixelDiff == 0) {
0677         maxY = std::max(p.y(), maxY);
0678         minY = std::min(p.y(), minY);
0679         prevPixelDiffZero = true;
0680         lastPoint = p;
0681     } else {
0682         if (prevPixelDiffZero) {
0683             if (maxY != minY)
0684                 lines.append(QLineF(lastPoint.x(), minY, lastPoint.x(), maxY));
0685             lines.append(QLineF(lastPoint, p));
0686         } else if (!std::isnan(lastPoint.x()) && !std::isnan(lastPoint.y()))
0687             lines.append(QLineF(lastPoint, p));
0688         prevPixelDiffZero = false;
0689         minY = p.y();
0690         maxY = p.y();
0691         lastPoint = p;
0692     }
0693 }
0694 
0695 void addUniqueLine_double_vector(double* p,
0696                                  double& minY,
0697                                  double& maxY,
0698                                  QPointF& lastPoint,
0699                                  const int& pixelDiff,
0700                                  QVector<QLineF>& lines,
0701                                  bool& prevPixelDiffZero) {
0702     if (pixelDiff == 0) {
0703         maxY = std::max(p[1], maxY);
0704         minY = std::min(p[1], minY);
0705         prevPixelDiffZero = true;
0706         lastPoint = QPointF(p[0], p[1]);
0707     } else {
0708         if (prevPixelDiffZero) {
0709             if (maxY != minY)
0710                 lines.append(QLineF(lastPoint.x(), minY, lastPoint.x(), maxY));
0711             lines.append(QLineF(lastPoint, QPointF(p[0], p[1])));
0712         } else if (!std::isnan(lastPoint.x()) && !std::isnan(lastPoint.y()))
0713             lines.append(QLineF(lastPoint, QPointF(p[0], p[1])));
0714         prevPixelDiffZero = false;
0715         minY = p[1];
0716         maxY = p[1];
0717         lastPoint = QPointF(p[0], p[1]);
0718     }
0719 }
0720 
0721 void addUniqueLine_double_vector_last_point_vector(double* p,
0722                                                    double& minY,
0723                                                    double& maxY,
0724                                                    double* lastPoint,
0725                                                    const int& pixelDiff,
0726                                                    QVector<QLineF>& lines,
0727                                                    bool& prevPixelDiffZero) {
0728     if (pixelDiff == 0) {
0729         maxY = std::max(p[1], maxY);
0730         minY = std::min(p[1], minY);
0731         prevPixelDiffZero = true;
0732         // lastPoint = QPointF(p[0], p[1]);
0733         lastPoint[0] = p[0];
0734         lastPoint[1] = p[1];
0735     } else {
0736         if (prevPixelDiffZero) {
0737             if (maxY != minY)
0738                 lines.append(QLineF(lastPoint[0], minY, lastPoint[0], maxY));
0739             lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0], p[1])));
0740         } else if (!std::isnan(lastPoint[0]) && !std::isnan(lastPoint[1]))
0741             lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0], p[1])));
0742         prevPixelDiffZero = false;
0743         minY = p[1];
0744         maxY = p[1];
0745         lastPoint[0] = p[0];
0746         lastPoint[1] = p[1];
0747     }
0748 }
0749 
0750 void addUniqueLine_double_vector_last_point_vector_lines_vector(double* p,
0751                                                                 double& minY,
0752                                                                 double& maxY,
0753                                                                 double* lastPoint,
0754                                                                 const int& pixelDiff,
0755                                                                 double* lines,
0756                                                                 bool& prevPixelDiffZero,
0757                                                                 int& numberLines) {
0758     if (pixelDiff == 0) {
0759         maxY = std::max(p[1], maxY);
0760         minY = std::min(p[1], minY);
0761         prevPixelDiffZero = true;
0762         // lastPoint = QPointF(p[0], p[1]);
0763         lastPoint[0] = p[0];
0764         lastPoint[1] = p[1];
0765     } else {
0766         if (prevPixelDiffZero) {
0767             if (maxY != minY) {
0768                 lines[4 * numberLines] = lastPoint[0];
0769                 lines[4 * numberLines + 1] = minY;
0770                 lines[4 * numberLines + 2] = lastPoint[0];
0771                 lines[4 * numberLines + 3] = maxY;
0772                 // lines.append(QLineF(lastPoint[0], minY, lastPoint[0], maxY));
0773                 numberLines++;
0774             }
0775             lines[4 * numberLines] = lastPoint[0];
0776             lines[4 * numberLines + 1] = lastPoint[1];
0777             lines[4 * numberLines + 2] = p[0];
0778             lines[4 * numberLines + 3] = p[1];
0779             numberLines++;
0780             // lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0],
0781             // p[1])));
0782         } else if (!std::isnan(lastPoint[0]) && !std::isnan(lastPoint[1])) {
0783             // lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0],
0784             // p[1])));
0785             lines[4 * numberLines] = lastPoint[0];
0786             lines[4 * numberLines + 1] = lastPoint[1];
0787             lines[4 * numberLines + 2] = p[0];
0788             lines[4 * numberLines + 3] = p[1];
0789             numberLines++;
0790         }
0791         prevPixelDiffZero = false;
0792         minY = p[1];
0793         maxY = p[1];
0794         lastPoint[0] = p[0];
0795         lastPoint[1] = p[1];
0796     }
0797 }
0798 
0799 void addUniqueLine_double_vector_last_point_vector_lines_vector_add4(double* p,
0800                                                                      double& minY,
0801                                                                      double& maxY,
0802                                                                      double* lastPoint,
0803                                                                      const int& pixelDiff,
0804                                                                      double* lines,
0805                                                                      bool& prevPixelDiffZero,
0806                                                                      int& numberLines) {
0807     if (pixelDiff == 0) {
0808         maxY = std::max(p[1], maxY);
0809         minY = std::min(p[1], minY);
0810         prevPixelDiffZero = true;
0811         // lastPoint = QPointF(p[0], p[1]);
0812         lastPoint[0] = p[0];
0813         lastPoint[1] = p[1];
0814     } else {
0815         if (prevPixelDiffZero) {
0816             if (maxY != minY) {
0817                 lines[numberLines] = lastPoint[0];
0818                 lines[numberLines + 1] = minY;
0819                 lines[numberLines + 2] = lastPoint[0];
0820                 lines[numberLines + 3] = maxY;
0821                 // lines.append(QLineF(lastPoint[0], minY, lastPoint[0], maxY));
0822                 numberLines += 4;
0823             }
0824             lines[numberLines] = lastPoint[0];
0825             lines[numberLines + 1] = lastPoint[1];
0826             lines[numberLines + 2] = p[0];
0827             lines[numberLines + 3] = p[1];
0828             numberLines += 4;
0829             // lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0],
0830             // p[1])));
0831         } else if (!std::isnan(lastPoint[0]) && !std::isnan(lastPoint[1])) {
0832             // lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0],
0833             // p[1])));
0834             lines[numberLines] = lastPoint[0];
0835             lines[numberLines + 1] = lastPoint[1];
0836             lines[numberLines + 2] = p[0];
0837             lines[numberLines + 3] = p[1];
0838             numberLines += 4;
0839         }
0840         prevPixelDiffZero = false;
0841         minY = p[1];
0842         maxY = p[1];
0843         lastPoint[0] = p[0];
0844         lastPoint[1] = p[1];
0845     }
0846 }
0847 
0848 void addUniqueLine_double_vector_last_point_vector_lines_vector_add4_dont_copy_last_point(double* p,
0849                                                                                           double& minY,
0850                                                                                           double& maxY,
0851                                                                                           double** lastPoint,
0852                                                                                           const int& pixelDiff,
0853                                                                                           double* lines,
0854                                                                                           bool& prevPixelDiffZero,
0855                                                                                           int& numberLines) {
0856     if (pixelDiff == 0) {
0857         maxY = std::max(p[1], maxY);
0858         minY = std::min(p[1], minY);
0859         prevPixelDiffZero = true;
0860         // lastPoint = QPointF(p[0], p[1]);
0861         // lastPoint = &p;
0862     } else {
0863         if (prevPixelDiffZero) {
0864             if (maxY != minY) {
0865                 lines[numberLines] = (*lastPoint)[0];
0866                 lines[numberLines + 1] = minY;
0867                 lines[numberLines + 2] = (*lastPoint)[0];
0868                 lines[numberLines + 3] = maxY;
0869                 // lines.append(QLineF(lastPoint[0], minY, lastPoint[0], maxY));
0870                 numberLines += 4;
0871             }
0872             lines[numberLines] = (*lastPoint)[0];
0873             lines[numberLines + 1] = (*lastPoint)[1];
0874             lines[numberLines + 2] = p[0];
0875             lines[numberLines + 3] = p[1];
0876             numberLines += 4;
0877             // lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0],
0878             // p[1])));
0879         } else if (!std::isnan((*lastPoint)[0]) && !std::isnan((*lastPoint)[1])) {
0880             // lines.append(QLineF(QPointF(lastPoint[0], lastPoint[1]), QPointF(p[0],
0881             // p[1])));
0882             lines[numberLines] = (*lastPoint)[0];
0883             lines[numberLines + 1] = (*lastPoint)[1];
0884             lines[numberLines + 2] = p[0];
0885             lines[numberLines + 3] = p[1];
0886             numberLines += 4;
0887         }
0888         prevPixelDiffZero = false;
0889         minY = p[1];
0890         maxY = p[1];
0891         // lastPoint = &p;
0892     }
0893 }
0894 
0895 void addUniqueLine02(QPointF p, double x, double& minY, double& maxY, QPointF& lastPoint, const int& pixelDiff, QVector<QLineF>& lines) {
0896     static bool prevPixelDiffZero = false;
0897     if (pixelDiff == 0) {
0898         maxY = std::max(p.y(), maxY);
0899         minY = std::min(p.y(), minY);
0900         lastPoint = p; // save last point
0901         prevPixelDiffZero = true;
0902     } else {
0903         static int i = 0;
0904         if (prevPixelDiffZero) {
0905             lines[i] = QLineF(x, maxY, x, minY);
0906             i++;
0907             lines[i] = QLineF(QPointF(x, lastPoint.y()), p);
0908         } else
0909             lines[i] = QLineF(lastPoint, p);
0910         i++;
0911         prevPixelDiffZero = false;
0912         minY = p.y();
0913         maxY = p.y();
0914         lastPoint = p;
0915     }
0916 }
0917 
0918 void XYCurveTest::updateLinesNoGapDirectConnection() {
0919     LOAD_PROJECT
0920     bool updateLinesCalled = false;
0921     connect(lastValueInvalidCurve,
0922             &XYCurve::linesUpdated,
0923             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
0924                 updateLinesCalled = true;
0925                 QVector<QLineF> refLines{
0926                     QLineF(QPointF(1, 1), QPointF(2, 2)),
0927                     QLineF(QPointF(2, 2), QPointF(3, 3)),
0928                     QLineF(QPointF(3, 3), QPointF(4, 7)),
0929                     QLineF(QPointF(4, 7), QPointF(5, 15)),
0930                     QLineF(QPointF(5, 15), QPointF(6, 3)),
0931                     QLineF(QPointF(6, 3), QPointF(7, -10)),
0932                     QLineF(QPointF(7, -10), QPointF(8, 0)),
0933                     QLineF(QPointF(8, 0), QPointF(9, 5)),
0934                     QLineF(QPointF(9, 5), QPointF(10, 8)),
0935                 };
0936                 QCOMPARE(lastValueInvalidCurvePrivate->m_logicalPoints.size(), refLines.size() + 1); // last row is invalid so it will be ommitted
0937                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
0938                 QCOMPARE(refLines.size(), test_lines.size());
0939                 for (int i = 0; i < test_lines.size(); i++) {
0940                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
0941                 }
0942             });
0943     lastValueInvalidCurvePrivate->updateLines();
0944     QCOMPARE(updateLinesCalled, true);
0945 }
0946 
0947 void XYCurveTest::updateLinesNoGapStartHorizontal() {
0948     LOAD_PROJECT
0949     bool updateLinesCalled = false;
0950     connect(lastValueInvalidCurve,
0951             &XYCurve::linesUpdated,
0952             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
0953                 updateLinesCalled = true;
0954                 QVector<QLineF> refLines = {
0955                     QLineF(QPointF(1, 1), QPointF(2, 1)),
0956                     QLineF(QPointF(2, 1), QPointF(2, 2)),
0957                     QLineF(QPointF(2, 2), QPointF(3, 2)),
0958                     QLineF(QPointF(3, 2), QPointF(3, 3)),
0959                     QLineF(QPointF(3, 3), QPointF(4, 3)),
0960                     QLineF(QPointF(4, 3), QPointF(4, 7)),
0961                     QLineF(QPointF(4, 7), QPointF(5, 7)),
0962                     QLineF(QPointF(5, 7), QPointF(5, 15)),
0963                     QLineF(QPointF(5, 15), QPointF(6, 15)),
0964                     QLineF(QPointF(6, 15), QPointF(6, 3)),
0965                     QLineF(QPointF(6, 3), QPointF(7, 3)),
0966                     QLineF(QPointF(7, 3), QPointF(7, -10)),
0967                     QLineF(QPointF(7, -10), QPointF(8, -10)),
0968                     QLineF(QPointF(8, -10), QPointF(8, 0)),
0969                     QLineF(QPointF(8, 0), QPointF(9, 0)),
0970                     QLineF(QPointF(9, 0), QPointF(9, 5)),
0971                     QLineF(QPointF(9, 5), QPointF(10, 5)),
0972                     QLineF(QPointF(10, 5), QPointF(10, 8)),
0973                 };
0974                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
0975                 QCOMPARE(refLines.size(), test_lines.size());
0976                 for (int i = 0; i < test_lines.size(); i++) {
0977                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
0978                 }
0979             });
0980     lastValueInvalidCurve->setLineType(XYCurve::LineType::StartHorizontal);
0981     QCOMPARE(updateLinesCalled, true);
0982 }
0983 
0984 void XYCurveTest::updateLinesNoGapStartVertical() {
0985     LOAD_PROJECT
0986     bool updateLinesCalled = false;
0987     connect(lastValueInvalidCurve,
0988             &XYCurve::linesUpdated,
0989             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
0990                 updateLinesCalled = true;
0991                 QVector<QLineF> refLines = {
0992                     QLineF(QPointF(1, 1), QPointF(1, 2)),
0993                     QLineF(QPointF(1, 2), QPointF(2, 2)),
0994                     QLineF(QPointF(2, 2), QPointF(2, 3)),
0995                     QLineF(QPointF(2, 3), QPointF(3, 3)),
0996                     QLineF(QPointF(3, 3), QPointF(3, 7)),
0997                     QLineF(QPointF(3, 7), QPointF(4, 7)),
0998                     QLineF(QPointF(4, 7), QPointF(4, 15)),
0999                     QLineF(QPointF(4, 15), QPointF(5, 15)),
1000                     QLineF(QPointF(5, 15), QPointF(5, 3)),
1001                     QLineF(QPointF(5, 3), QPointF(6, 3)),
1002                     QLineF(QPointF(6, 3), QPointF(6, -10)),
1003                     QLineF(QPointF(6, -10), QPointF(7, -10)),
1004                     QLineF(QPointF(7, -10), QPointF(7, 0)),
1005                     QLineF(QPointF(7, 0), QPointF(8, 0)),
1006                     QLineF(QPointF(8, 0), QPointF(8, 5)),
1007                     QLineF(QPointF(8, 5), QPointF(9, 5)),
1008                     QLineF(QPointF(9, 5), QPointF(9, 8)),
1009                     QLineF(QPointF(9, 8), QPointF(10, 8)),
1010                 };
1011                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
1012                 QCOMPARE(refLines.size(), test_lines.size());
1013                 for (int i = 0; i < test_lines.size(); i++) {
1014                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1015                 }
1016             });
1017     lastValueInvalidCurve->setLineType(XYCurve::LineType::StartVertical);
1018     QCOMPARE(updateLinesCalled, true);
1019 }
1020 
1021 void XYCurveTest::updateLinesNoGapMidPointHorizontal() {
1022     LOAD_PROJECT
1023     bool updateLinesCalled = false;
1024     connect(lastValueInvalidCurve,
1025             &XYCurve::linesUpdated,
1026             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1027                 updateLinesCalled = true;
1028                 QVector<QLineF> refLines = {
1029                     QLineF(QPointF(1, 1), QPointF(1.5, 1)),     QLineF(QPointF(1.5, 1), QPointF(1.5, 2)),   QLineF(QPointF(1.5, 2), QPointF(2, 2)),
1030                     QLineF(QPointF(2, 2), QPointF(2.5, 2)),     QLineF(QPointF(2.5, 2), QPointF(2.5, 3)),   QLineF(QPointF(2.5, 3), QPointF(3, 3)),
1031                     QLineF(QPointF(3, 3), QPointF(3.5, 3)),     QLineF(QPointF(3.5, 3), QPointF(3.5, 7)),   QLineF(QPointF(3.5, 7), QPointF(4, 7)),
1032                     QLineF(QPointF(4, 7), QPointF(4.5, 7)),     QLineF(QPointF(4.5, 7), QPointF(4.5, 15)),  QLineF(QPointF(4.5, 15), QPointF(5, 15)),
1033                     QLineF(QPointF(5, 15), QPointF(5.5, 15)),   QLineF(QPointF(5.5, 15), QPointF(5.5, 3)),  QLineF(QPointF(5.5, 3), QPointF(6, 3)),
1034                     QLineF(QPointF(6, 3), QPointF(6.5, 3)),     QLineF(QPointF(6.5, 3), QPointF(6.5, -10)), QLineF(QPointF(6.5, -10), QPointF(7, -10)),
1035                     QLineF(QPointF(7, -10), QPointF(7.5, -10)), QLineF(QPointF(7.5, -10), QPointF(7.5, 0)), QLineF(QPointF(7.5, 0), QPointF(8, 0)),
1036                     QLineF(QPointF(8, 0), QPointF(8.5, 0)),     QLineF(QPointF(8.5, 0), QPointF(8.5, 5)),   QLineF(QPointF(8.5, 5), QPointF(9, 5)),
1037                     QLineF(QPointF(9, 5), QPointF(9.5, 5)),     QLineF(QPointF(9.5, 5), QPointF(9.5, 8)),   QLineF(QPointF(9.5, 8), QPointF(10, 8)),
1038 
1039                 };
1040                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
1041                 QCOMPARE(refLines.size(), test_lines.size());
1042                 for (int i = 0; i < test_lines.size(); i++) {
1043                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1044                 }
1045             });
1046     lastValueInvalidCurve->setLineType(XYCurve::LineType::MidpointHorizontal);
1047     QCOMPARE(updateLinesCalled, true);
1048 }
1049 
1050 void XYCurveTest::updateLinesNoGapMidPointVertical() {
1051     LOAD_PROJECT
1052     bool updateLinesCalled = false;
1053     connect(lastValueInvalidCurve,
1054             &XYCurve::linesUpdated,
1055             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1056                 updateLinesCalled = true;
1057                 QVector<QLineF> refLines = {
1058                     QLineF(QPointF(1, 1), QPointF(1, 1.5)),
1059                     QLineF(QPointF(1, 1.5), QPointF(2, 1.5)),
1060                     //      QLineF(QPointF(2, 1.5), QPointF(2, 2)),
1061                     //      QLineF(QPointF(2, 2), QPointF(2, 2.5)),
1062                     QLineF(QPointF(2, 1.5), QPointF(2, 2.5)),
1063 
1064                     QLineF(QPointF(2, 2.5), QPointF(3, 2.5)),
1065                     //      QLineF(QPointF(3, 2.5), QPointF(3, 3)),
1066                     //      QLineF(QPointF(3, 3), QPointF(3, 5)),
1067                     QLineF(QPointF(3, 2.5), QPointF(3, 5)),
1068 
1069                     QLineF(QPointF(3, 5), QPointF(4, 5)),
1070                     //      QLineF(QPointF(4, 5), QPointF(4, 7)),
1071                     //      QLineF(QPointF(4, 7), QPointF(4, 11)),
1072                     QLineF(QPointF(4, 5), QPointF(4, 11)),
1073 
1074                     QLineF(QPointF(4, 11), QPointF(5, 11)),
1075                     //      QLineF(QPointF(5, 11), QPointF(5, 15)),
1076                     //      QLineF(QPointF(5, 15), QPointF(5, 9)),
1077                     QLineF(QPointF(5, 9), QPointF(5, 15)),
1078 
1079                     QLineF(QPointF(5, 9), QPointF(6, 9)),
1080                     //      QLineF(QPointF(6, 9), QPointF(6, 3)),
1081                     //      QLineF(QPointF(6, 3), QPointF(6, -3.5)),
1082                     QLineF(QPointF(6, 9), QPointF(6, -3.5)),
1083 
1084                     QLineF(QPointF(6, -3.5), QPointF(7, -3.5)),
1085                     //      QLineF(QPointF(7, -3.5), QPointF(7, -10)),
1086                     //      QLineF(QPointF(7, -10), QPointF(7, -5)),
1087                     QLineF(QPointF(7, -10), QPointF(7, -3.5)),
1088 
1089                     QLineF(QPointF(7, -5), QPointF(8, -5)),
1090                     //      QLineF(QPointF(8, -5), QPointF(8, 0)),
1091                     //      QLineF(QPointF(8, 0), QPointF(8, 2.5)),
1092                     QLineF(QPointF(8, -5), QPointF(8, 2.5)),
1093 
1094                     QLineF(QPointF(8, 2.5), QPointF(9, 2.5)),
1095                     //      QLineF(QPointF(9, 2.5), QPointF(9, 5)),
1096                     //      QLineF(QPointF(9, 5), QPointF(9, 6.5)),
1097                     QLineF(QPointF(9, 2.5), QPointF(9, 6.5)),
1098 
1099                     QLineF(QPointF(9, 6.5), QPointF(10, 6.5)),
1100                     QLineF(QPointF(10, 6.5), QPointF(10, 8)),
1101                 };
1102                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
1103                 QCOMPARE(refLines.size(), test_lines.size());
1104                 for (int i = 0; i < test_lines.size(); i++) {
1105                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1106                 }
1107             });
1108     lastValueInvalidCurve->setLineType(XYCurve::LineType::MidpointVertical);
1109     QCOMPARE(updateLinesCalled, true);
1110 }
1111 
1112 void XYCurveTest::updateLinesNoGapSegments2() {
1113     LOAD_PROJECT
1114     bool updateLinesCalled = false;
1115     connect(lastValueInvalidCurve,
1116             &XYCurve::linesUpdated,
1117             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1118                 updateLinesCalled = true;
1119                 QVector<QLineF> refLines = {
1120                     QLineF(QPointF(1, 1), QPointF(2, 2)),
1121                     //      QLineF(QPointF(2, 2), QPointF(3, 3)),
1122                     QLineF(QPointF(3, 3), QPointF(4, 7)),
1123                     //      QLineF(QPointF(4, 7), QPointF(5, 15)),
1124                     QLineF(QPointF(5, 15), QPointF(6, 3)),
1125                     //      QLineF(QPointF(6, 3), QPointF(7, -10)),
1126                     QLineF(QPointF(7, -10), QPointF(8, 0)),
1127                     //      QLineF(QPointF(8, 0), QPointF(9, 5)),
1128                     QLineF(QPointF(9, 5), QPointF(10, 8)),
1129                 };
1130                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
1131                 QCOMPARE(refLines.size(), test_lines.size());
1132                 for (int i = 0; i < test_lines.size(); i++) {
1133                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1134                 }
1135             });
1136     lastValueInvalidCurve->setLineType(XYCurve::LineType::Segments2);
1137     QCOMPARE(updateLinesCalled, true);
1138 }
1139 
1140 void XYCurveTest::updateLinesNoGapSegments3() {
1141     LOAD_PROJECT
1142     bool updateLinesCalled = false;
1143     connect(lastValueInvalidCurve,
1144             &XYCurve::linesUpdated,
1145             [lastValueInvalidCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1146                 updateLinesCalled = true;
1147                 QVector<QLineF> refLines = {
1148                     QLineF(QPointF(1, 1), QPointF(2, 2)),
1149                     QLineF(QPointF(2, 2), QPointF(3, 3)),
1150                     //      QLineF(QPointF(3, 3), QPointF(4, 7)),
1151                     QLineF(QPointF(4, 7), QPointF(5, 15)),
1152                     QLineF(QPointF(5, 15), QPointF(6, 3)),
1153                     //      QLineF(QPointF(6, 3), QPointF(7, -10)),
1154                     QLineF(QPointF(7, -10), QPointF(8, 0)),
1155                     QLineF(QPointF(8, 0), QPointF(9, 5)),
1156                     //      QLineF(QPointF(9, 5), QPointF(10, 8)),
1157                 };
1158                 auto test_lines = lastValueInvalidCurvePrivate->m_lines;
1159                 QCOMPARE(refLines.size(), test_lines.size());
1160                 for (int i = 0; i < test_lines.size(); i++) {
1161                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1162                 }
1163             });
1164     lastValueInvalidCurve->setLineType(XYCurve::LineType::Segments3);
1165     QCOMPARE(updateLinesCalled, true);
1166 }
1167 
1168 void XYCurveTest::updateLinesNoGapDirectConnectionLastVertical() {
1169     LOAD_PROJECT
1170     bool updateLinesCalled = false;
1171     connect(lastVerticalCurve,
1172             &XYCurve::linesUpdated,
1173             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1174                 updateLinesCalled = true;
1175                 QVector<QLineF> refLines{
1176                     QLineF(QPointF(1, 1), QPointF(2, 2)),
1177                     QLineF(QPointF(2, 2), QPointF(3, 3)),
1178                     QLineF(QPointF(3, 3), QPointF(4, 7)),
1179                     QLineF(QPointF(4, 7), QPointF(5, 15)),
1180                     QLineF(QPointF(5, 15), QPointF(6, 3)),
1181                     QLineF(QPointF(6, 3), QPointF(7, -10)),
1182                     QLineF(QPointF(7, -10), QPointF(8, 0)),
1183                     QLineF(QPointF(8, 0), QPointF(9, 5)),
1184                     QLineF(QPointF(9, 5), QPointF(9, 8)),
1185                 };
1186                 QCOMPARE(lastVerticalCurvePrivate->m_logicalPoints.size(), refLines.size() + 1); // last row is invalid so it will be ommitted
1187                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1188                 QCOMPARE(refLines.size(), test_lines.size());
1189                 for (int i = 0; i < test_lines.size(); i++) {
1190                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1191                 }
1192             });
1193     lastVerticalCurvePrivate->updateLines();
1194     QCOMPARE(updateLinesCalled, true);
1195 }
1196 
1197 void XYCurveTest::updateLinesNoGapStartHorizontalLastVertical() {
1198     LOAD_PROJECT
1199     bool updateLinesCalled = false;
1200     connect(lastVerticalCurve,
1201             &XYCurve::linesUpdated,
1202             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1203                 updateLinesCalled = true;
1204                 QVector<QLineF> refLines = {
1205                     QLineF(QPointF(1, 1), QPointF(2, 1)),
1206                     QLineF(QPointF(2, 1), QPointF(2, 2)),
1207                     QLineF(QPointF(2, 2), QPointF(3, 2)),
1208                     QLineF(QPointF(3, 2), QPointF(3, 3)),
1209                     QLineF(QPointF(3, 3), QPointF(4, 3)),
1210                     QLineF(QPointF(4, 3), QPointF(4, 7)),
1211                     QLineF(QPointF(4, 7), QPointF(5, 7)),
1212                     QLineF(QPointF(5, 7), QPointF(5, 15)),
1213                     QLineF(QPointF(5, 15), QPointF(6, 15)),
1214                     QLineF(QPointF(6, 15), QPointF(6, 3)),
1215                     QLineF(QPointF(6, 3), QPointF(7, 3)),
1216                     QLineF(QPointF(7, 3), QPointF(7, -10)),
1217                     QLineF(QPointF(7, -10), QPointF(8, -10)),
1218                     QLineF(QPointF(8, -10), QPointF(8, 0)),
1219                     QLineF(QPointF(8, 0), QPointF(9, 0)),
1220                     QLineF(QPointF(9, 0), QPointF(9, 8)),
1221                 };
1222                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1223                 QCOMPARE(refLines.size(), test_lines.size());
1224                 for (int i = 0; i < test_lines.size(); i++) {
1225                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1226                 }
1227             });
1228     lastVerticalCurve->setLineType(XYCurve::LineType::StartHorizontal);
1229     QCOMPARE(updateLinesCalled, true);
1230 }
1231 
1232 void XYCurveTest::updateLinesNoGapStartVerticalLastVertical() {
1233     LOAD_PROJECT
1234     bool updateLinesCalled = false;
1235     connect(lastVerticalCurve,
1236             &XYCurve::linesUpdated,
1237             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1238                 updateLinesCalled = true;
1239                 QVector<QLineF> refLines = {
1240                     QLineF(QPointF(1, 1), QPointF(1, 2)),
1241                     QLineF(QPointF(1, 2), QPointF(2, 2)),
1242                     QLineF(QPointF(2, 2), QPointF(2, 3)),
1243                     QLineF(QPointF(2, 3), QPointF(3, 3)),
1244                     QLineF(QPointF(3, 3), QPointF(3, 7)),
1245                     QLineF(QPointF(3, 7), QPointF(4, 7)),
1246                     QLineF(QPointF(4, 7), QPointF(4, 15)),
1247                     QLineF(QPointF(4, 15), QPointF(5, 15)),
1248                     QLineF(QPointF(5, 15), QPointF(5, 3)),
1249                     QLineF(QPointF(5, 3), QPointF(6, 3)),
1250                     QLineF(QPointF(6, 3), QPointF(6, -10)),
1251                     QLineF(QPointF(6, -10), QPointF(7, -10)),
1252                     QLineF(QPointF(7, -10), QPointF(7, 0)),
1253                     QLineF(QPointF(7, 0), QPointF(8, 0)),
1254                     QLineF(QPointF(8, 0), QPointF(8, 5)),
1255                     QLineF(QPointF(8, 5), QPointF(9, 5)),
1256                     QLineF(QPointF(9, 5), QPointF(9, 8)),
1257                 };
1258                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1259                 QCOMPARE(refLines.size(), test_lines.size());
1260                 for (int i = 0; i < test_lines.size(); i++) {
1261                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1262                 }
1263             });
1264     lastVerticalCurve->setLineType(XYCurve::LineType::StartVertical);
1265     QCOMPARE(updateLinesCalled, true);
1266 }
1267 
1268 void XYCurveTest::updateLinesNoGapMidPointHorizontalLastVertical() {
1269     LOAD_PROJECT
1270     bool updateLinesCalled = false;
1271     connect(lastVerticalCurve,
1272             &XYCurve::linesUpdated,
1273             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1274                 updateLinesCalled = true;
1275                 QVector<QLineF> refLines = {
1276                     QLineF(QPointF(1, 1), QPointF(1.5, 1)),     QLineF(QPointF(1.5, 1), QPointF(1.5, 2)),   QLineF(QPointF(1.5, 2), QPointF(2, 2)),
1277                     QLineF(QPointF(2, 2), QPointF(2.5, 2)),     QLineF(QPointF(2.5, 2), QPointF(2.5, 3)),   QLineF(QPointF(2.5, 3), QPointF(3, 3)),
1278                     QLineF(QPointF(3, 3), QPointF(3.5, 3)),     QLineF(QPointF(3.5, 3), QPointF(3.5, 7)),   QLineF(QPointF(3.5, 7), QPointF(4, 7)),
1279                     QLineF(QPointF(4, 7), QPointF(4.5, 7)),     QLineF(QPointF(4.5, 7), QPointF(4.5, 15)),  QLineF(QPointF(4.5, 15), QPointF(5, 15)),
1280                     QLineF(QPointF(5, 15), QPointF(5.5, 15)),   QLineF(QPointF(5.5, 15), QPointF(5.5, 3)),  QLineF(QPointF(5.5, 3), QPointF(6, 3)),
1281                     QLineF(QPointF(6, 3), QPointF(6.5, 3)),     QLineF(QPointF(6.5, 3), QPointF(6.5, -10)), QLineF(QPointF(6.5, -10), QPointF(7, -10)),
1282                     QLineF(QPointF(7, -10), QPointF(7.5, -10)), QLineF(QPointF(7.5, -10), QPointF(7.5, 0)), QLineF(QPointF(7.5, 0), QPointF(8, 0)),
1283                     QLineF(QPointF(8, 0), QPointF(8.5, 0)),     QLineF(QPointF(8.5, 0), QPointF(8.5, 5)),   QLineF(QPointF(8.5, 5), QPointF(9, 5)),
1284                     QLineF(QPointF(9, 5), QPointF(9, 8)),
1285                 };
1286                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1287                 QCOMPARE(refLines.size(), test_lines.size());
1288                 for (int i = 0; i < test_lines.size(); i++) {
1289                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1290                 }
1291             });
1292     lastVerticalCurve->setLineType(XYCurve::LineType::MidpointHorizontal);
1293     QCOMPARE(updateLinesCalled, true);
1294 }
1295 
1296 void XYCurveTest::updateLinesNoGapMidPointVerticalLastVertical() {
1297     LOAD_PROJECT
1298     bool updateLinesCalled = false;
1299     connect(lastVerticalCurve,
1300             &XYCurve::linesUpdated,
1301             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1302                 updateLinesCalled = true;
1303                 QVector<QLineF> refLines = {
1304                     QLineF(QPointF(1, 1), QPointF(1, 1.5)),
1305                     QLineF(QPointF(1, 1.5), QPointF(2, 1.5)),
1306                     //      QLineF(QPointF(2, 1.5), QPointF(2, 2)),
1307                     //      QLineF(QPointF(2, 2), QPointF(2, 2.5)),
1308                     QLineF(QPointF(2, 1.5), QPointF(2, 2.5)),
1309 
1310                     QLineF(QPointF(2, 2.5), QPointF(3, 2.5)),
1311                     //      QLineF(QPointF(3, 2.5), QPointF(3, 3)),
1312                     //      QLineF(QPointF(3, 3), QPointF(3, 5)),
1313                     QLineF(QPointF(3, 2.5), QPointF(3, 5)),
1314 
1315                     QLineF(QPointF(3, 5), QPointF(4, 5)),
1316                     //      QLineF(QPointF(4, 5), QPointF(4, 7)),
1317                     //      QLineF(QPointF(4, 7), QPointF(4, 11)),
1318                     QLineF(QPointF(4, 5), QPointF(4, 11)),
1319 
1320                     QLineF(QPointF(4, 11), QPointF(5, 11)),
1321                     //      QLineF(QPointF(5, 11), QPointF(5, 15)),
1322                     //      QLineF(QPointF(5, 15), QPointF(5, 9)),
1323                     QLineF(QPointF(5, 9), QPointF(5, 15)),
1324 
1325                     QLineF(QPointF(5, 9), QPointF(6, 9)),
1326                     //      QLineF(QPointF(6, 9), QPointF(6, 3)),
1327                     //      QLineF(QPointF(6, 3), QPointF(6, -3.5)),
1328                     QLineF(QPointF(6, 9), QPointF(6, -3.5)),
1329 
1330                     QLineF(QPointF(6, -3.5), QPointF(7, -3.5)),
1331                     //      QLineF(QPointF(7, -3.5), QPointF(7, -10)),
1332                     //      QLineF(QPointF(7, -10), QPointF(7, -5)),
1333                     QLineF(QPointF(7, -10), QPointF(7, -3.5)),
1334 
1335                     QLineF(QPointF(7, -5), QPointF(8, -5)),
1336                     //      QLineF(QPointF(8, -5), QPointF(8, 0)),
1337                     //      QLineF(QPointF(8, 0), QPointF(8, 2.5)),
1338                     QLineF(QPointF(8, -5), QPointF(8, 2.5)),
1339 
1340                     QLineF(QPointF(8, 2.5), QPointF(9, 2.5)),
1341                     //      QLineF(QPointF(9, 2.5), QPointF(9, 5)),
1342                     //      QLineF(QPointF(9, 5), QPointF(9, 6.5)),
1343                     QLineF(QPointF(9, 2.5), QPointF(9, 8)),
1344                 };
1345                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1346                 QCOMPARE(refLines.size(), test_lines.size());
1347                 for (int i = 0; i < test_lines.size(); i++) {
1348                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1349                 }
1350             });
1351     lastVerticalCurve->setLineType(XYCurve::LineType::MidpointVertical);
1352     QCOMPARE(updateLinesCalled, true);
1353 }
1354 
1355 void XYCurveTest::updateLinesNoGapSegments2LastVertical() {
1356     LOAD_PROJECT
1357     bool updateLinesCalled = false;
1358     connect(lastVerticalCurve,
1359             &XYCurve::linesUpdated,
1360             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1361                 updateLinesCalled = true;
1362                 QVector<QLineF> refLines = {
1363                     QLineF(QPointF(1, 1), QPointF(2, 2)),
1364                     //      QLineF(QPointF(2, 2), QPointF(3, 3)),
1365                     QLineF(QPointF(3, 3), QPointF(4, 7)),
1366                     //      QLineF(QPointF(4, 7), QPointF(5, 15)),
1367                     QLineF(QPointF(5, 15), QPointF(6, 3)),
1368                     //      QLineF(QPointF(6, 3), QPointF(7, -10)),
1369                     QLineF(QPointF(7, -10), QPointF(8, 0)),
1370                     //      QLineF(QPointF(8, 0), QPointF(9, 5)),
1371                     QLineF(QPointF(9, 5), QPointF(9, 8)),
1372                 };
1373                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1374                 QCOMPARE(refLines.size(), test_lines.size());
1375                 for (int i = 0; i < test_lines.size(); i++) {
1376                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1377                 }
1378             });
1379     lastVerticalCurve->setLineType(XYCurve::LineType::Segments2);
1380     QCOMPARE(updateLinesCalled, true);
1381 }
1382 
1383 void XYCurveTest::updateLinesNoGapSegments3LastVertical() {
1384     LOAD_PROJECT
1385     bool updateLinesCalled = false;
1386     connect(lastVerticalCurve,
1387             &XYCurve::linesUpdated,
1388             [lastVerticalCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1389                 updateLinesCalled = true;
1390                 QVector<QLineF> refLines = {
1391                     QLineF(QPointF(1, 1), QPointF(2, 2)),
1392                     QLineF(QPointF(2, 2), QPointF(3, 3)),
1393                     //      QLineF(QPointF(3, 3), QPointF(4, 7)),
1394                     QLineF(QPointF(4, 7), QPointF(5, 15)),
1395                     QLineF(QPointF(5, 15), QPointF(6, 3)),
1396                     //      QLineF(QPointF(6, 3), QPointF(7, -10)),
1397                     QLineF(QPointF(7, -10), QPointF(8, 0)),
1398                     QLineF(QPointF(8, 0), QPointF(9, 5)),
1399                     //      QLineF(QPointF(9, 5), QPointF(9, 8)),
1400                 };
1401                 auto test_lines = lastVerticalCurvePrivate->m_lines;
1402                 QCOMPARE(refLines.size(), test_lines.size());
1403                 for (int i = 0; i < test_lines.size(); i++) {
1404                     COMPARE_LINES(test_lines.at(i), refLines.at(i));
1405                 }
1406             });
1407     lastVerticalCurve->setLineType(XYCurve::LineType::Segments3);
1408     QCOMPARE(updateLinesCalled, true);
1409 }
1410 
1411 void XYCurveTest::updateLinesWithGapLineSkipDirectConnection() {
1412     LOAD_PROJECT
1413     withGapCurve->setLineSkipGaps(true);
1414     bool updateLinesCalled = false;
1415     connect(withGapCurve, &XYCurve::linesUpdated, [withGapCurvePrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1416         updateLinesCalled = true;
1417         QVector<QLineF> refLines{
1418             QLineF(QPointF(1, 1), QPointF(2, 2)),
1419             QLineF(QPointF(2, 2), QPointF(3, 3)),
1420             QLineF(QPointF(3, 3), QPointF(5, 5)),
1421             QLineF(QPointF(5, 5), QPointF(6, 6)),
1422         };
1423         QCOMPARE(withGapCurvePrivate->m_logicalPoints.size(), refLines.size() + 1);
1424         auto test_lines = withGapCurvePrivate->m_lines;
1425         QCOMPARE(refLines.size(), test_lines.size());
1426         for (int i = 0; i < test_lines.size(); i++) {
1427             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1428         }
1429     });
1430     withGapCurvePrivate->updateLines();
1431     QCOMPARE(updateLinesCalled, true);
1432 }
1433 
1434 // ######################################################################################
1435 //  With Gap, skipGaps = True
1436 // ######################################################################################
1437 void XYCurveTest::updateLinesWithGapLineSkipDirectConnection2() {
1438     LOAD_PROJECT
1439     bool updateLinesCalled = false;
1440     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1441         updateLinesCalled = true;
1442         QVector<QLineF> refLines{
1443             QLineF(QPointF(1, 1), QPointF(2, 2)),
1444             QLineF(QPointF(2, 2), QPointF(3, 3)),
1445             QLineF(QPointF(3, 3), QPointF(4, 7)),
1446             QLineF(QPointF(4, 7), QPointF(6, 3)),
1447             QLineF(QPointF(6, 3), QPointF(7, -10)),
1448             QLineF(QPointF(7, -10), QPointF(8, 0)),
1449             QLineF(QPointF(8, 0), QPointF(9, 5)),
1450             QLineF(QPointF(9, 5), QPointF(10, 8)),
1451         };
1452         QCOMPARE(withGapCurve2Private->m_logicalPoints.size(), refLines.size() + 1); // last row is invalid so it will be ommitted
1453         auto test_lines = withGapCurve2Private->m_lines;
1454         QCOMPARE(refLines.size(), test_lines.size());
1455         for (int i = 0; i < test_lines.size(); i++) {
1456             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1457         }
1458     });
1459     withGapCurve2->setLineSkipGaps(true);
1460     QCOMPARE(updateLinesCalled, true);
1461 }
1462 
1463 void XYCurveTest::updateLinesWithGapLineSkipStartHorizontal() {
1464     LOAD_PROJECT
1465     withGapCurve2->setLineType(XYCurve::LineType::StartHorizontal);
1466     bool updateLinesCalled = false;
1467     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1468         updateLinesCalled = true;
1469         QVector<QLineF> refLines = {
1470             QLineF(QPointF(1, 1), QPointF(2, 1)),
1471             QLineF(QPointF(2, 1), QPointF(2, 2)),
1472             QLineF(QPointF(2, 2), QPointF(3, 2)),
1473             QLineF(QPointF(3, 2), QPointF(3, 3)),
1474             QLineF(QPointF(3, 3), QPointF(4, 3)),
1475             QLineF(QPointF(4, 3), QPointF(4, 7)),
1476             QLineF(QPointF(4, 7), QPointF(6, 7)),
1477             QLineF(QPointF(6, 7), QPointF(6, 3)),
1478             QLineF(QPointF(6, 3), QPointF(7, 3)),
1479             QLineF(QPointF(7, 3), QPointF(7, -10)),
1480             QLineF(QPointF(7, -10), QPointF(8, -10)),
1481             QLineF(QPointF(8, -10), QPointF(8, 0)),
1482             QLineF(QPointF(8, 0), QPointF(9, 0)),
1483             QLineF(QPointF(9, 0), QPointF(9, 5)),
1484             QLineF(QPointF(9, 5), QPointF(10, 5)),
1485             QLineF(QPointF(10, 5), QPointF(10, 8)),
1486         };
1487         auto test_lines = withGapCurve2Private->m_lines;
1488         QCOMPARE(refLines.size(), test_lines.size());
1489         for (int i = 0; i < test_lines.size(); i++) {
1490             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1491         }
1492     });
1493     withGapCurve2->setLineSkipGaps(true);
1494     QCOMPARE(updateLinesCalled, true);
1495 }
1496 
1497 void XYCurveTest::updateLinesWithGapLineSkipStartVertical() {
1498     LOAD_PROJECT
1499 
1500     withGapCurve2->setLineType(XYCurve::LineType::StartVertical);
1501     bool updateLinesCalled = false;
1502     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1503         updateLinesCalled = true;
1504         QVector<QLineF> refLines = {
1505             QLineF(QPointF(1, 1), QPointF(1, 2)),
1506             QLineF(QPointF(1, 2), QPointF(2, 2)),
1507             QLineF(QPointF(2, 2), QPointF(2, 3)),
1508             QLineF(QPointF(2, 3), QPointF(3, 3)),
1509             QLineF(QPointF(3, 3), QPointF(3, 7)),
1510             QLineF(QPointF(3, 7), QPointF(4, 7)),
1511             QLineF(QPointF(4, 7), QPointF(4, 3)),
1512             QLineF(QPointF(4, 3), QPointF(6, 3)),
1513             QLineF(QPointF(6, 3), QPointF(6, -10)),
1514             QLineF(QPointF(6, -10), QPointF(7, -10)),
1515             QLineF(QPointF(7, -10), QPointF(7, 0)),
1516             QLineF(QPointF(7, 0), QPointF(8, 0)),
1517             QLineF(QPointF(8, 0), QPointF(8, 5)),
1518             QLineF(QPointF(8, 5), QPointF(9, 5)),
1519             QLineF(QPointF(9, 5), QPointF(9, 8)),
1520             QLineF(QPointF(9, 8), QPointF(10, 8)),
1521         };
1522         auto test_lines = withGapCurve2Private->m_lines;
1523         QCOMPARE(refLines.size(), test_lines.size());
1524         for (int i = 0; i < test_lines.size(); i++) {
1525             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1526         }
1527     });
1528     withGapCurve2->setLineSkipGaps(true);
1529     QCOMPARE(updateLinesCalled, true);
1530 }
1531 
1532 void XYCurveTest::updateLinesWithGapLineSkipMidPointHorizontal() {
1533     LOAD_PROJECT
1534 
1535     withGapCurve2->setLineType(XYCurve::LineType::MidpointHorizontal);
1536     bool updateLinesCalled = false;
1537     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1538         updateLinesCalled = true;
1539         QVector<QLineF> refLines = {
1540             QLineF(QPointF(1, 1), QPointF(1.5, 1)),     QLineF(QPointF(1.5, 1), QPointF(1.5, 2)),   QLineF(QPointF(1.5, 2), QPointF(2, 2)),
1541             QLineF(QPointF(2, 2), QPointF(2.5, 2)),     QLineF(QPointF(2.5, 2), QPointF(2.5, 3)),   QLineF(QPointF(2.5, 3), QPointF(3, 3)),
1542             QLineF(QPointF(3, 3), QPointF(3.5, 3)),     QLineF(QPointF(3.5, 3), QPointF(3.5, 7)),   QLineF(QPointF(3.5, 7), QPointF(4, 7)),
1543             QLineF(QPointF(4, 7), QPointF(5, 7)),       QLineF(QPointF(5, 7), QPointF(5, 3)),       QLineF(QPointF(5, 3), QPointF(6, 3)),
1544             QLineF(QPointF(6, 3), QPointF(6.5, 3)),     QLineF(QPointF(6.5, 3), QPointF(6.5, -10)), QLineF(QPointF(6.5, -10), QPointF(7, -10)),
1545             QLineF(QPointF(7, -10), QPointF(7.5, -10)), QLineF(QPointF(7.5, -10), QPointF(7.5, 0)), QLineF(QPointF(7.5, 0), QPointF(8, 0)),
1546             QLineF(QPointF(8, 0), QPointF(8.5, 0)),     QLineF(QPointF(8.5, 0), QPointF(8.5, 5)),   QLineF(QPointF(8.5, 5), QPointF(9, 5)),
1547             QLineF(QPointF(9, 5), QPointF(9.5, 5)),     QLineF(QPointF(9.5, 5), QPointF(9.5, 8)),   QLineF(QPointF(9.5, 8), QPointF(10, 8)),
1548 
1549         };
1550         auto test_lines = withGapCurve2Private->m_lines;
1551         QCOMPARE(refLines.size(), test_lines.size());
1552         for (int i = 0; i < test_lines.size(); i++) {
1553             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1554         }
1555     });
1556     withGapCurve2->setLineSkipGaps(true);
1557     QCOMPARE(updateLinesCalled, true);
1558 }
1559 
1560 void XYCurveTest::updateLinesWithGapLineSkipMidPointVertical() {
1561     LOAD_PROJECT
1562 
1563     withGapCurve2->setLineType(XYCurve::LineType::MidpointVertical);
1564     bool updateLinesCalled = false;
1565     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1566         updateLinesCalled = true;
1567         QVector<QLineF> refLines = {
1568             QLineF(QPointF(1, 1), QPointF(1, 1.5)), // vertical
1569             QLineF(QPointF(1, 1.5), QPointF(2, 1.5)),
1570             //      QLineF(QPointF(2, 1.5), QPointF(2, 2)),
1571             //      QLineF(QPointF(2, 2), QPointF(2, 2.5)),
1572             QLineF(QPointF(2, 1.5), QPointF(2, 2.5)), // vertical
1573 
1574             QLineF(QPointF(2, 2.5), QPointF(3, 2.5)),
1575             //      QLineF(QPointF(3, 2.5), QPointF(3, 3)),
1576             //      QLineF(QPointF(3, 3), QPointF(3, 5)),
1577             QLineF(QPointF(3, 2.5), QPointF(3, 5)), // vertical
1578 
1579             QLineF(QPointF(3, 5), QPointF(4, 5)),
1580             //      QLineF(QPointF(4, 5), QPointF(4, 7)),
1581             //      QLineF(QPointF(4, 7), QPointF(4, 5)),
1582             QLineF(QPointF(4, 5), QPointF(4, 7)), // vertical
1583 
1584             QLineF(QPointF(4, 5), QPointF(6, 5)),
1585             //      QLineF(QPointF(6, 5), QPointF(6, 3)),
1586             //      QLineF(QPointF(6, 3), QPointF(6, -3.5)),
1587             QLineF(QPointF(6, 5), QPointF(6, -3.5)), // vertical
1588 
1589             QLineF(QPointF(6, -3.5), QPointF(7, -3.5)),
1590             //      QLineF(QPointF(7, -3.5), QPointF(7, -10)),
1591             //      QLineF(QPointF(7, -10), QPointF(7, -5)),
1592             QLineF(QPointF(7, -10), QPointF(7, -3.5)), // vertical
1593 
1594             QLineF(QPointF(7, -5), QPointF(8, -5)),
1595             //      QLineF(QPointF(8, -5), QPointF(8, 0)),
1596             //      QLineF(QPointF(8, 0), QPointF(8, 2.5)),
1597             QLineF(QPointF(8, -5), QPointF(8, 2.5)), // vertical
1598 
1599             QLineF(QPointF(8, 2.5), QPointF(9, 2.5)),
1600             //      QLineF(QPointF(9, 2.5), QPointF(9, 5)),
1601             //      QLineF(QPointF(9, 5), QPointF(9, 6.5)),
1602             QLineF(QPointF(9, 2.5), QPointF(9, 6.5)), // vertical
1603 
1604             QLineF(QPointF(9, 6.5), QPointF(10, 6.5)),
1605             QLineF(QPointF(10, 6.5), QPointF(10, 8)), // vertical
1606         };
1607         auto test_lines = withGapCurve2Private->m_lines;
1608         // QCOMPARE(refLines.size(), test_lines.size());
1609         for (int i = 0; i < test_lines.size(); i++) {
1610             DEBUG(i);
1611             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1612         }
1613     });
1614 
1615     withGapCurve2->setLineSkipGaps(true);
1616     QCOMPARE(updateLinesCalled, true);
1617 }
1618 
1619 void XYCurveTest::updateLinesWithGapLineSkipSegments2() {
1620     LOAD_PROJECT
1621 
1622     withGapCurve2->setLineType(XYCurve::LineType::Segments2);
1623     bool updateLinesCalled = false;
1624     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1625         updateLinesCalled = true;
1626         QVector<QLineF> refLines = {
1627             QLineF(QPointF(1, 1), QPointF(2, 2)),
1628             //      QLineF(QPointF(2, 2), QPointF(3, 3)),
1629             QLineF(QPointF(3, 3), QPointF(4, 7)),
1630             //      QLineF(QPointF(4, 7), QPointF(6, 3)),
1631             QLineF(QPointF(6, 3), QPointF(7, -10)),
1632             //      QLineF(QPointF(7, -10), QPointF(8, 0)),
1633             QLineF(QPointF(8, 0), QPointF(9, 5)),
1634             //      QLineF(QPointF(9, 5), QPointF(10, 8)),
1635         };
1636         auto test_lines = withGapCurve2Private->m_lines;
1637         QCOMPARE(refLines.size(), test_lines.size());
1638         for (int i = 0; i < test_lines.size(); i++) {
1639             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1640         }
1641     });
1642     withGapCurve2->setLineSkipGaps(true);
1643     QCOMPARE(updateLinesCalled, true);
1644 }
1645 
1646 void XYCurveTest::updateLinesWithGapLineSkipSegments3() {
1647     LOAD_PROJECT
1648 
1649     withGapCurve2->setLineType(XYCurve::LineType::Segments3);
1650     bool updateLinesCalled = false;
1651     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1652         updateLinesCalled = true;
1653         QVector<QLineF> refLines = {
1654             QLineF(QPointF(1, 1), QPointF(2, 2)),
1655             QLineF(QPointF(2, 2), QPointF(3, 3)),
1656             //      QLineF(QPointF(3, 3), QPointF(4, 7)),
1657             QLineF(QPointF(4, 7), QPointF(6, 3)),
1658             QLineF(QPointF(6, 3), QPointF(7, -10)),
1659             //      QLineF(QPointF(7, -10), QPointF(8, 0)),
1660             QLineF(QPointF(8, 0), QPointF(9, 5)),
1661             QLineF(QPointF(9, 5), QPointF(10, 8)),
1662         };
1663         auto test_lines = withGapCurve2Private->m_lines;
1664         QCOMPARE(refLines.size(), test_lines.size());
1665         for (int i = 0; i < test_lines.size(); i++) {
1666             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1667         }
1668     });
1669     withGapCurve2->setLineSkipGaps(true);
1670     QCOMPARE(updateLinesCalled, true);
1671 }
1672 
1673 // ######################################################################################
1674 //  With Gap, skipGaps = false
1675 // ######################################################################################
1676 void XYCurveTest::updateLinesWithGapDirectConnection() {
1677     LOAD_PROJECT
1678     withGapCurve2->setLineSkipGaps(true);
1679     bool updateLinesCalled = false;
1680     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1681         updateLinesCalled = true;
1682         QVector<QLineF> refLines{
1683             QLineF(QPointF(1, 1), QPointF(2, 2)),
1684             QLineF(QPointF(2, 2), QPointF(3, 3)),
1685             QLineF(QPointF(3, 3), QPointF(4, 7)),
1686             QLineF(QPointF(6, 3), QPointF(7, -10)),
1687             QLineF(QPointF(7, -10), QPointF(8, 0)),
1688             QLineF(QPointF(8, 0), QPointF(9, 5)),
1689             QLineF(QPointF(9, 5), QPointF(10, 8)),
1690         };
1691         QCOMPARE(withGapCurve2Private->m_logicalPoints.size() - 2, refLines.size()); // one point will be skipped, so 2 lines less
1692         auto test_lines = withGapCurve2Private->m_lines;
1693         QCOMPARE(refLines.size(), test_lines.size());
1694         for (int i = 0; i < test_lines.size(); i++) {
1695             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1696         }
1697     });
1698 
1699     withGapCurve2->setLineSkipGaps(false);
1700     QCOMPARE(updateLinesCalled, true);
1701 }
1702 
1703 void XYCurveTest::updateLinesWithGapStartHorizontal() {
1704     LOAD_PROJECT
1705 
1706     withGapCurve2->setLineType(XYCurve::LineType::StartHorizontal);
1707     withGapCurve2->setLineSkipGaps(true);
1708     bool updateLinesCalled = false;
1709     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1710         updateLinesCalled = true;
1711         QVector<QLineF> refLines = {
1712             QLineF(QPointF(1, 1), QPointF(2, 1)),
1713             QLineF(QPointF(2, 1), QPointF(2, 2)),
1714             QLineF(QPointF(2, 2), QPointF(3, 2)),
1715             QLineF(QPointF(3, 2), QPointF(3, 3)),
1716             QLineF(QPointF(3, 3), QPointF(4, 3)),
1717             QLineF(QPointF(4, 3), QPointF(4, 7)),
1718             QLineF(QPointF(6, 3), QPointF(7, 3)),
1719             QLineF(QPointF(7, 3), QPointF(7, -10)),
1720             QLineF(QPointF(7, -10), QPointF(8, -10)),
1721             QLineF(QPointF(8, -10), QPointF(8, 0)),
1722             QLineF(QPointF(8, 0), QPointF(9, 0)),
1723             QLineF(QPointF(9, 0), QPointF(9, 5)),
1724             QLineF(QPointF(9, 5), QPointF(10, 5)),
1725             QLineF(QPointF(10, 5), QPointF(10, 8)),
1726         };
1727         auto test_lines = withGapCurve2Private->m_lines;
1728         // QCOMPARE(refLines.size(), test_lines.size());
1729         for (int i = 0; i < test_lines.size(); i++) {
1730             DEBUG(i)
1731             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1732         }
1733     });
1734     withGapCurve2->setLineSkipGaps(false);
1735     QCOMPARE(updateLinesCalled, true);
1736 }
1737 
1738 void XYCurveTest::updateLinesWithGapStartVertical() {
1739     LOAD_PROJECT
1740 
1741     withGapCurve2->setLineType(XYCurve::LineType::StartVertical);
1742     withGapCurve2->setLineSkipGaps(true);
1743     bool updateLinesCalled = false;
1744     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1745         updateLinesCalled = true;
1746         QVector<QLineF> refLines = {
1747             QLineF(QPointF(1, 1), QPointF(1, 2)),
1748             QLineF(QPointF(1, 2), QPointF(2, 2)),
1749             QLineF(QPointF(2, 2), QPointF(2, 3)),
1750             QLineF(QPointF(2, 3), QPointF(3, 3)),
1751             QLineF(QPointF(3, 3), QPointF(3, 7)),
1752             QLineF(QPointF(3, 7), QPointF(4, 7)),
1753             QLineF(QPointF(6, 3), QPointF(6, -10)),
1754             QLineF(QPointF(6, -10), QPointF(7, -10)),
1755             QLineF(QPointF(7, -10), QPointF(7, 0)),
1756             QLineF(QPointF(7, 0), QPointF(8, 0)),
1757             QLineF(QPointF(8, 0), QPointF(8, 5)),
1758             QLineF(QPointF(8, 5), QPointF(9, 5)),
1759             QLineF(QPointF(9, 5), QPointF(9, 8)),
1760             QLineF(QPointF(9, 8), QPointF(10, 8)),
1761         };
1762         auto test_lines = withGapCurve2Private->m_lines;
1763         QCOMPARE(refLines.size(), test_lines.size());
1764         for (int i = 0; i < test_lines.size(); i++) {
1765             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1766         }
1767     });
1768 
1769     withGapCurve2->setLineSkipGaps(false);
1770     QCOMPARE(updateLinesCalled, true);
1771 }
1772 
1773 void XYCurveTest::updateLinesWithGapMidPointHorizontal() {
1774     LOAD_PROJECT
1775 
1776     withGapCurve2->setLineType(XYCurve::LineType::MidpointHorizontal);
1777     withGapCurve2->setLineSkipGaps(true);
1778     bool updateLinesCalled = false;
1779     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1780         updateLinesCalled = true;
1781         QVector<QLineF> refLines = {
1782             QLineF(QPointF(1, 1), QPointF(1.5, 1)),     QLineF(QPointF(1.5, 1), QPointF(1.5, 2)),   QLineF(QPointF(1.5, 2), QPointF(2, 2)),
1783             QLineF(QPointF(2, 2), QPointF(2.5, 2)),     QLineF(QPointF(2.5, 2), QPointF(2.5, 3)),   QLineF(QPointF(2.5, 3), QPointF(3, 3)),
1784             QLineF(QPointF(3, 3), QPointF(3.5, 3)),     QLineF(QPointF(3.5, 3), QPointF(3.5, 7)),   QLineF(QPointF(3.5, 7), QPointF(4, 7)),
1785             QLineF(QPointF(6, 3), QPointF(6.5, 3)),     QLineF(QPointF(6.5, 3), QPointF(6.5, -10)), QLineF(QPointF(6.5, -10), QPointF(7, -10)),
1786             QLineF(QPointF(7, -10), QPointF(7.5, -10)), QLineF(QPointF(7.5, -10), QPointF(7.5, 0)), QLineF(QPointF(7.5, 0), QPointF(8, 0)),
1787             QLineF(QPointF(8, 0), QPointF(8.5, 0)),     QLineF(QPointF(8.5, 0), QPointF(8.5, 5)),   QLineF(QPointF(8.5, 5), QPointF(9, 5)),
1788             QLineF(QPointF(9, 5), QPointF(9.5, 5)),     QLineF(QPointF(9.5, 5), QPointF(9.5, 8)),   QLineF(QPointF(9.5, 8), QPointF(10, 8)),
1789 
1790         };
1791         auto test_lines = withGapCurve2Private->m_lines;
1792         QCOMPARE(refLines.size(), test_lines.size());
1793         for (int i = 0; i < test_lines.size(); i++) {
1794             DEBUG(i)
1795             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1796         }
1797     });
1798 
1799     withGapCurve2->setLineSkipGaps(false);
1800     QCOMPARE(updateLinesCalled, true);
1801 }
1802 
1803 void XYCurveTest::updateLinesWithGapMidPointVertical() {
1804     LOAD_PROJECT
1805 
1806     withGapCurve2->setLineType(XYCurve::LineType::MidpointVertical);
1807     withGapCurve2->setLineSkipGaps(true);
1808     bool updateLinesCalled = false;
1809     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1810         updateLinesCalled = true;
1811         QVector<QLineF> refLines = {
1812             QLineF(QPointF(1, 1), QPointF(1, 1.5)),
1813             QLineF(QPointF(1, 1.5), QPointF(2, 1.5)),
1814             //      QLineF(QPointF(2, 1.5), QPointF(2, 2)),
1815             //      QLineF(QPointF(2, 2), QPointF(2, 2.5)),
1816             QLineF(QPointF(2, 1.5), QPointF(2, 2.5)),
1817 
1818             QLineF(QPointF(2, 2.5), QPointF(3, 2.5)),
1819             //      QLineF(QPointF(3, 2.5), QPointF(3, 3)),
1820             //      QLineF(QPointF(3, 3), QPointF(3, 5)),
1821             QLineF(QPointF(3, 2.5), QPointF(3, 5)), // vertical
1822 
1823             QLineF(QPointF(3, 5), QPointF(4, 5)),
1824             QLineF(QPointF(4, 5), QPointF(4, 7)),
1825             // GAP
1826             QLineF(QPointF(6, 3), QPointF(6, -3.5)),
1827 
1828             QLineF(QPointF(6, -3.5), QPointF(7, -3.5)),
1829             //      QLineF(QPointF(7, -3.5), QPointF(7, -10)),
1830             //      QLineF(QPointF(7, -10), QPointF(7, -5)),
1831             QLineF(QPointF(7, -10), QPointF(7, -3.5)),
1832 
1833             QLineF(QPointF(7, -5), QPointF(8, -5)),
1834             //      QLineF(QPointF(8, -5), QPointF(8, 0)),
1835             //      QLineF(QPointF(8, 0), QPointF(8, 2.5)),
1836             QLineF(QPointF(8, -5), QPointF(8, 2.5)),
1837 
1838             QLineF(QPointF(8, 2.5), QPointF(9, 2.5)),
1839             //      QLineF(QPointF(9, 2.5), QPointF(9, 5)),
1840             //      QLineF(QPointF(9, 5), QPointF(9, 6.5)),
1841             QLineF(QPointF(9, 2.5), QPointF(9, 6.5)),
1842 
1843             QLineF(QPointF(9, 6.5), QPointF(10, 6.5)),
1844             QLineF(QPointF(10, 6.5), QPointF(10, 8)),
1845         };
1846         auto test_lines = withGapCurve2Private->m_lines;
1847         QCOMPARE(refLines.size(), test_lines.size());
1848         for (int i = 0; i < test_lines.size(); i++) {
1849             DEBUG(i)
1850             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1851         }
1852     });
1853     withGapCurve2->setLineSkipGaps(false);
1854     QCOMPARE(updateLinesCalled, true);
1855 }
1856 
1857 void XYCurveTest::updateLinesWithGapSegments2() {
1858     LOAD_PROJECT
1859 
1860     withGapCurve2->setLineType(XYCurve::LineType::Segments2);
1861     withGapCurve2->setLineSkipGaps(true);
1862     bool updateLinesCalled = false;
1863     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1864         updateLinesCalled = true;
1865         QVector<QLineF> refLines = {
1866             QLineF(QPointF(1, 1), QPointF(2, 2)),
1867             //      QLineF(QPointF(2, 2), QPointF(3, 3)),
1868             QLineF(QPointF(3, 3), QPointF(4, 7)),
1869             //      QLineF(QPointF(6, 3), QPointF(7, -10)),
1870             QLineF(QPointF(7, -10), QPointF(8, 0)),
1871             //      QLineF(QPointF(8, 0), QPointF(9, 5)),
1872             QLineF(QPointF(9, 5), QPointF(10, 8)),
1873         };
1874         auto test_lines = withGapCurve2Private->m_lines;
1875         QCOMPARE(refLines.size(), test_lines.size());
1876         for (int i = 0; i < test_lines.size(); i++) {
1877             DEBUG(i)
1878             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1879         }
1880     });
1881 
1882     withGapCurve2->setLineSkipGaps(false);
1883     QCOMPARE(updateLinesCalled, true);
1884 }
1885 
1886 void XYCurveTest::updateLinesWithGapSegments3() {
1887     LOAD_PROJECT
1888 
1889     withGapCurve2->setLineType(XYCurve::LineType::Segments3);
1890     withGapCurve2->setLineSkipGaps(true);
1891     bool updateLinesCalled = false;
1892     connect(withGapCurve2, &XYCurve::linesUpdated, [withGapCurve2Private, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1893         updateLinesCalled = true;
1894         QVector<QLineF> refLines = {
1895             QLineF(QPointF(1, 1), QPointF(2, 2)),
1896             QLineF(QPointF(2, 2), QPointF(3, 3)),
1897             //      QLineF(QPointF(3, 3), QPointF(4, 7)),
1898             QLineF(QPointF(6, 3), QPointF(7, -10)),
1899             QLineF(QPointF(7, -10), QPointF(8, 0)),
1900             //      QLineF(QPointF(8, 0), QPointF(9, 5)),
1901             QLineF(QPointF(9, 5), QPointF(10, 8)),
1902         };
1903         auto test_lines = withGapCurve2Private->m_lines;
1904         QCOMPARE(refLines.size(), test_lines.size());
1905         for (int i = 0; i < test_lines.size(); i++) {
1906             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1907         }
1908     });
1909 
1910     withGapCurve2->setLineSkipGaps(false);
1911     QCOMPARE(updateLinesCalled, true);
1912 }
1913 
1914 /*!
1915  * \brief XYCurveTest::updateLinesLog10
1916  * Testing curve with nonlinear x range
1917  */
1918 void XYCurveTest::updateLinesLog10() {
1919     LOAD_PROJECT
1920     bool updateLinesCalled = false;
1921     connect(linear, &XYCurve::linesUpdated, [linearPrivate, &updateLinesCalled](const XYCurve* /*curve*/, const QVector<QLineF>& /*lines*/) {
1922         updateLinesCalled = true;
1923         QVector<QLineF> refLines{
1924             QLineF(QPointF(0.1, 0.1), QPointF(1.2, 1.2)),
1925             QLineF(QPointF(1.2, 1.2), QPointF(2.3, 2.3)),
1926             QLineF(QPointF(2.3, 2.3), QPointF(3.4, 3.4)),
1927             QLineF(QPointF(3.4, 3.4), QPointF(4.5, 4.5)),
1928             QLineF(QPointF(4.5, 4.5), QPointF(5.6, 5.6)),
1929             QLineF(QPointF(5.6, 5.6), QPointF(6.7, 6.7)),
1930             QLineF(QPointF(6.7, 6.7), QPointF(7.8, 7.8)),
1931             QLineF(QPointF(7.8, 7.8), QPointF(8.9, 8.9)),
1932             QLineF(QPointF(8.9, 8.9), QPointF(10, 10)),
1933         };
1934         QCOMPARE(linearPrivate->m_logicalPoints.size(), refLines.size() + 1); // last row is invalid so it will be ommitted
1935         auto test_lines = linearPrivate->m_lines;
1936         QCOMPARE(refLines.size(), test_lines.size());
1937         for (int i = 0; i < test_lines.size(); i++) {
1938             COMPARE_LINES(test_lines.at(i), refLines.at(i));
1939         }
1940     });
1941     linearPrivate->updateLines();
1942     QCOMPARE(updateLinesCalled, true);
1943 }
1944 
1945 // TODO: create tests for Splines
1946 
1947 // ############################################################################
1948 //  Hover tests
1949 // ############################################################################
1950 void XYCurveTest::hooverCurveIntegerEndingZeros() {
1951     LOAD_HOVER_PROJECT
1952 
1953     QPointF mouseLogicalPos(13, 29.1); // extracted from the spreadsheet
1954     bool visible;
1955     auto mouseScenePos = plot->coordinateSystem(integerNonMonotonic->coordinateSystemIndex())->mapLogicalToScene(mouseLogicalPos, visible);
1956     QCOMPARE(integerNonMonotonic->activatePlot(mouseScenePos, -1), true);
1957 }
1958 
1959 QTEST_MAIN(XYCurveTest)