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"