File indexing completed on 2024-05-19 15:26:47

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include <QtTest/QtTest>
0008 
0009 #include <vector>
0010 #include "math/bezier/bezier_length.hpp"
0011 
0012 using namespace glaxnimate::math::bezier;
0013 
0014 #define CLOSE_ENOUGH(a, b, ret) \
0015 do {\
0016     if (!close_enough(a, b, 0.5, #a, #b, __FILE__, __LINE__) && ret)\
0017         return;\
0018 } while (false)
0019 
0020 
0021 class TestCase: public QObject
0022 {
0023     Q_OBJECT
0024 
0025 private:
0026     bool close_enough(qreal actual, qreal expected, qreal tolerance, const char* actual_name, const char* expected_name, const char *file, int line)
0027     {
0028         auto delta = qAbs(actual - expected);
0029         if ( delta > tolerance )
0030         {
0031             int max = qMax(strlen(actual_name), strlen(expected_name));
0032             std::string msg = "Compared values are too different\n";
0033             msg += "    Actual   ";
0034             msg += actual_name;
0035             msg += std::string(max - strlen(actual_name), ' ');
0036             msg += ": ";
0037             msg += std::to_string(actual);
0038             msg += "\n    Expected ";
0039             msg += expected_name;
0040             msg += std::string(max - strlen(expected_name), ' ');
0041             msg += ": ";
0042             msg += std::to_string(expected);
0043             msg += "\n    Delta    ";
0044             msg += std::string(max, ' ');
0045             msg += ": ";
0046             msg += std::to_string(delta);
0047             QTest::qFail(msg.c_str(), file, line);
0048             return false;
0049         }
0050 
0051         return true;
0052     }
0053 private Q_SLOTS:
0054     void test_basics()
0055     {
0056         for ( qreal off = 0; off <= 100; off += 50 )
0057         {
0058             for ( qreal len = 50; len <= 150; len += 50 )
0059             {
0060                 Solver seg{{off, 0}, {off + len/3., 0}, {off + len*2./3., 0}, {off + len, 0}};
0061                 LengthData data(seg, 10);
0062                 QCOMPARE(data.length(), len);
0063             }
0064         }
0065     }
0066 
0067     void test_sloped()
0068     {
0069         Solver seg{{0, 0}, {0, 0}, {30, 40}, {30, 40}};
0070         LengthData data(seg, 10);
0071         QCOMPARE(data.length(), 50);
0072     }
0073 
0074     void test_segment_line_uniform()
0075     {
0076         Solver seg{{0, 0}, {33.333, 0}, {66.667, 0}, {100, 0}};
0077         LengthData data(seg, 10);
0078         QCOMPARE(data.length(), 100);
0079 
0080         for ( int i = 0; i <= 100; i += 10 )
0081         {
0082             CLOSE_ENOUGH(seg.solve(data.at_length(i).ratio).x(), i, false);
0083         }
0084     }
0085 
0086     void test_segment_line_bunched_up()
0087     {
0088         Solver seg{{0, 0}, {0, 0}, {100, 0}, {100, 0}};
0089         LengthData data(seg, 10);
0090         QCOMPARE(data.length(), 100);
0091 
0092         for ( int i = 0; i <= 100; i += 10 )
0093         {
0094             CLOSE_ENOUGH(seg.solve(data.at_length(i).ratio).x(), i, false);
0095         }
0096     }
0097 
0098     void test_bez_line_uniform()
0099     {
0100         Bezier bez;
0101         bez.add_point({0, 0}, {0, 0}, {50./3., 0});
0102         bez.add_point({50, 0}, {-50./3., 0}, {150./3., 0});
0103         bez.add_point({200, 0}, {-150./3., 0});
0104 
0105         LengthData data(bez, 10);
0106         QCOMPARE(data.length(), 200);
0107 
0108         for ( int i = 0; i <= 200; i += 10 )
0109         {
0110             auto split = data.at_length(i);
0111             Solver seg(bez.segment(split.index));
0112             CLOSE_ENOUGH(seg.solve(split.descend().ratio).x(), i, false);
0113         }
0114     }
0115 
0116     void test_bez_line_bunched_up()
0117     {
0118         Bezier bez;
0119         bez.add_point({0, 0});
0120         bez.add_point({50, 0});
0121         bez.add_point({200, 0});
0122 
0123         LengthData data(bez, 16);
0124         QCOMPARE(data.length(), 200);
0125 
0126         for ( int i = 0; i <= 200; i += 10 )
0127         {
0128             auto split = data.at_length(i);
0129             Solver seg(bez.segment(split.index));
0130             CLOSE_ENOUGH(seg.solve(split.descend().ratio).x(), i, false);
0131         }
0132     }
0133 
0134     void test_multibez_line_bunched_up()
0135     {
0136         MultiBezier mbez;
0137         mbez.move_to({0, 0});
0138         mbez.line_to({50, 0});
0139         mbez.line_to({200, 0});
0140         mbez.move_to({0, 100});
0141         mbez.line_to({50, 100});
0142         mbez.line_to({200, 100});
0143 
0144         LengthData data(mbez, 16);
0145         QCOMPARE(data.length(), 400);
0146 
0147         for ( int i = 0; i < 200; i += 10 )
0148         {
0149             auto split = data.at_length(i);
0150             QCOMPARE(split.index, 0);
0151             QCOMPARE(split.length, i);
0152             auto child_split = split.descend();
0153             if ( i < 50 )
0154                 QCOMPARE(child_split.index, 0);
0155             else
0156                 QCOMPARE(child_split.index, 1);
0157             Solver seg(mbez.beziers()[split.index].segment(child_split.index));
0158             CLOSE_ENOUGH(seg.solve(child_split.descend().ratio).x(), i, false);
0159             CLOSE_ENOUGH(seg.solve(child_split.descend().ratio).y(), 0, false);
0160         }
0161 
0162         for ( int i = 200; i <= 400; i += 10 )
0163         {
0164             auto split = data.at_length(i);
0165             QCOMPARE(split.index, 1);
0166             QCOMPARE(split.length, i - 200);
0167             auto child_split = split.descend();
0168             if ( i < 250 )
0169                 QCOMPARE(child_split.index, 0);
0170             else
0171                 QCOMPARE(child_split.index, 1);
0172             Solver seg(mbez.beziers()[split.index].segment(child_split.index));
0173             CLOSE_ENOUGH(seg.solve(child_split.descend().ratio).x(), i - 200, false);
0174             CLOSE_ENOUGH(seg.solve(child_split.descend().ratio).y(), 100, false);
0175         }
0176     }
0177 };
0178 
0179 QTEST_GUILESS_MAIN(TestCase)
0180 #include "test_bezier_length.moc"