File indexing completed on 2024-12-22 04:10:13
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_cage_transform_worker_test.h" 0008 0009 #include <simpletest.h> 0010 0011 #include <KoProgressUpdater.h> 0012 #include <KoUpdater.h> 0013 0014 #include <testutil.h> 0015 #include <kistest.h> 0016 0017 #include <kis_cage_transform_worker.h> 0018 #include <algorithm> 0019 0020 void testCage(bool clockwise, bool unityTransform, bool benchmarkPrepareOnly = false, int pixelPrecision = 8, bool testQImage = false) 0021 { 0022 TestUtil::TestProgressBar bar; 0023 KoProgressUpdater pu(&bar); 0024 KoUpdaterPtr updater = pu.startSubtask(); 0025 0026 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); 0027 QImage image(TestUtil::fetchDataFileLazy("test_cage_transform.png")); 0028 0029 KisPaintDeviceSP dev = new KisPaintDevice(cs); 0030 dev->convertFromQImage(image, 0); 0031 0032 KisPaintDeviceSP srcDev = new KisPaintDevice(*dev); 0033 0034 QVector<QPointF> origPoints; 0035 QVector<QPointF> transfPoints; 0036 0037 QRectF bounds(dev->exactBounds()); 0038 0039 origPoints << bounds.topLeft(); 0040 origPoints << 0.5 * (bounds.topLeft() + bounds.topRight()); 0041 origPoints << 0.5 * (bounds.topLeft() + bounds.bottomRight()); 0042 origPoints << 0.5 * (bounds.topRight() + bounds.bottomRight()); 0043 origPoints << bounds.bottomRight(); 0044 origPoints << bounds.bottomLeft(); 0045 0046 if (!clockwise) { 0047 std::reverse(origPoints.begin(), origPoints.end()); 0048 } 0049 0050 if (unityTransform) { 0051 transfPoints = origPoints; 0052 } else { 0053 transfPoints << bounds.topLeft(); 0054 transfPoints << 0.5 * (bounds.topLeft() + bounds.topRight()); 0055 transfPoints << 0.5 * (bounds.bottomLeft() + bounds.bottomRight()); 0056 transfPoints << 0.5 * (bounds.bottomLeft() + bounds.bottomRight()) + 0057 (bounds.bottomLeft() - bounds.topLeft()); 0058 transfPoints << bounds.bottomLeft() + 0059 (bounds.bottomLeft() - bounds.topLeft()); 0060 transfPoints << bounds.bottomLeft(); 0061 0062 if (!clockwise) { 0063 std::reverse(transfPoints.begin(), transfPoints.end()); 0064 } 0065 } 0066 0067 KisCageTransformWorker worker(dev->region().boundingRect(), 0068 origPoints, 0069 updater, 0070 pixelPrecision); 0071 0072 QImage result; 0073 QPointF srcQImageOffset(0, 0); 0074 QPointF dstQImageOffset; 0075 0076 QBENCHMARK_ONCE { 0077 if (!testQImage) { 0078 worker.prepareTransform(); 0079 if (!benchmarkPrepareOnly) { 0080 worker.setTransformedCage(transfPoints); 0081 worker.run(srcDev, dev); 0082 0083 } 0084 } else { 0085 QImage srcImage = image; 0086 QImage image2 = QImage(image.size(), QImage::Format_ARGB32); 0087 QPainter gc(&image2); 0088 gc.drawImage(QPoint(), srcImage); 0089 gc.end(); 0090 image = image2; 0091 0092 KisCageTransformWorker qimageWorker(image, 0093 srcQImageOffset, 0094 origPoints, 0095 updater, 0096 pixelPrecision); 0097 qimageWorker.prepareTransform(); 0098 qimageWorker.setTransformedCage(transfPoints); 0099 result = qimageWorker.runOnQImage(&dstQImageOffset); 0100 } 0101 } 0102 0103 QString testName = QString("%1_%2") 0104 .arg(clockwise ? "clk" : "cclk") 0105 .arg(unityTransform ? "unity" : "normal"); 0106 0107 if (testQImage) { 0108 QVERIFY(TestUtil::checkQImage(result, "cage_transform_test", "cage_qimage", testName, 1, 1)); 0109 } else if (!benchmarkPrepareOnly && pixelPrecision == 8) { 0110 0111 result = dev->convertToQImage(0); 0112 QVERIFY(TestUtil::checkQImage(result, "cage_transform_test", "cage", testName, 1, 1)); 0113 } 0114 } 0115 0116 void KisCageTransformWorkerTest::testCageClockwise() 0117 { 0118 testCage(true, false); 0119 } 0120 0121 void KisCageTransformWorkerTest::testCageClockwisePrepareOnly() 0122 { 0123 testCage(true, false, true); 0124 } 0125 0126 void KisCageTransformWorkerTest::testCageClockwisePixelPrecision4() 0127 { 0128 testCage(true, false, false, 4); 0129 } 0130 0131 void KisCageTransformWorkerTest::testCageClockwisePixelPrecision8QImage() 0132 { 0133 testCage(true, false, false, 8, true); 0134 } 0135 0136 void KisCageTransformWorkerTest::testCageCounterclockwise() 0137 { 0138 testCage(false, false); 0139 } 0140 0141 void KisCageTransformWorkerTest::testCageClockwiseUnity() 0142 { 0143 testCage(true, true); 0144 } 0145 0146 void KisCageTransformWorkerTest::testCageCounterclockwiseUnity() 0147 { 0148 testCage(false, true); 0149 } 0150 0151 #include <QtGlobal> 0152 0153 0154 QPointF generatePoint(const QRectF &rc) 0155 { 0156 qreal cx = qreal(qrand()) / RAND_MAX; 0157 qreal cy = qreal(qrand()) / RAND_MAX; 0158 0159 QPointF diff = rc.bottomRight() - rc.topLeft(); 0160 0161 QPointF pt = rc.topLeft() + QPointF(cx * diff.x(), cy * diff.y()); 0162 return pt; 0163 } 0164 0165 void KisCageTransformWorkerTest::stressTestRandomCages() 0166 { 0167 TestUtil::TestProgressBar bar; 0168 KoProgressUpdater pu(&bar); 0169 KoUpdaterPtr updater = pu.startSubtask(); 0170 0171 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); 0172 QImage image(TestUtil::fetchDataFileLazy("test_cage_transform.png")); 0173 0174 KisPaintDeviceSP dev = new KisPaintDevice(cs); 0175 dev->convertFromQImage(image, 0); 0176 0177 KisPaintDeviceSP dstDev = new KisPaintDevice(cs); 0178 0179 const int pixelPrecision = 8; 0180 QRectF bounds(dev->exactBounds()); 0181 0182 qsrand(1); 0183 0184 for (int numPoints = 4; numPoints < 15; numPoints+=5) { 0185 for (int j = 0; j < 200; j++) { 0186 QVector<QPointF> origPoints; 0187 QVector<QPointF> transfPoints; 0188 0189 dbgKrita << ppVar(j); 0190 0191 for (int i = 0; i < numPoints; i++) { 0192 origPoints << generatePoint(bounds); 0193 transfPoints << generatePoint(bounds); 0194 } 0195 0196 // no just hope it doesn't crash ;) 0197 KisCageTransformWorker worker(dev->region().boundingRect(), 0198 origPoints, 0199 updater, 0200 pixelPrecision); 0201 worker.prepareTransform(); 0202 worker.setTransformedCage(transfPoints); 0203 worker.run(dev, dstDev); 0204 } 0205 } 0206 } 0207 0208 #include "kis_green_coordinates_math.h" 0209 0210 void KisCageTransformWorkerTest::testUnityGreenCoordinates() 0211 { 0212 QVector<QPointF> origPoints; 0213 QVector<QPointF> transfPoints; 0214 0215 QRectF bounds(0,0,300,300); 0216 0217 origPoints << bounds.topLeft(); 0218 origPoints << 0.5 * (bounds.topLeft() + bounds.topRight()); 0219 origPoints << 0.5 * (bounds.topLeft() + bounds.bottomRight()); 0220 origPoints << 0.5 * (bounds.topRight() + bounds.bottomRight()); 0221 origPoints << bounds.bottomRight(); 0222 origPoints << bounds.bottomLeft(); 0223 0224 transfPoints = origPoints; 0225 0226 QVector<QPointF> points; 0227 points << QPointF(10,10); 0228 points << QPointF(140,10); 0229 points << QPointF(140,140); 0230 points << QPointF(10,140); 0231 0232 points << QPointF(10,160); 0233 points << QPointF(140,160); 0234 points << QPointF(140,290); 0235 points << QPointF(10,290); 0236 0237 points << QPointF(160,160); 0238 points << QPointF(290,160); 0239 points << QPointF(290,290); 0240 points << QPointF(160,290); 0241 0242 KisGreenCoordinatesMath cage; 0243 0244 cage.precalculateGreenCoordinates(origPoints, points); 0245 cage.generateTransformedCageNormals(transfPoints); 0246 0247 QVector<QPointF> newPoints; 0248 0249 for (int i = 0; i < points.size(); i++) { 0250 newPoints << cage.transformedPoint(i, transfPoints); 0251 QCOMPARE(points[i], newPoints.last()); 0252 } 0253 } 0254 0255 #include "kis_algebra_2d.h" 0256 0257 void KisCageTransformWorkerTest::testTransformAsBase() 0258 { 0259 QPointF t(1.0, 0.0); 0260 QPointF b1(1.0, 0.0); 0261 QPointF b2(2.0, 0.0); 0262 QPointF result; 0263 0264 0265 t = QPointF(1.0, 0.0); 0266 b1 = QPointF(1.0, 0.0); 0267 b2 = QPointF(2.0, 0.0); 0268 result = KisAlgebra2D::transformAsBase(t, b1, b2); 0269 QCOMPARE(result, QPointF(2.0, 0.0)); 0270 0271 t = QPointF(1.0, 0.0); 0272 b1 = QPointF(1.0, 0.0); 0273 b2 = QPointF(0.0, 1.0); 0274 result = KisAlgebra2D::transformAsBase(t, b1, b2); 0275 QCOMPARE(result, QPointF(0.0, 1.0)); 0276 0277 t = QPointF(1.0, 0.0); 0278 b1 = QPointF(1.0, 0.0); 0279 b2 = QPointF(0.0, 2.0); 0280 result = KisAlgebra2D::transformAsBase(t, b1, b2); 0281 QCOMPARE(result, QPointF(0.0, 2.0)); 0282 0283 t = QPointF(0.0, 1.0); 0284 b1 = QPointF(1.0, 0.0); 0285 b2 = QPointF(2.0, 0.0); 0286 result = KisAlgebra2D::transformAsBase(t, b1, b2); 0287 QCOMPARE(result, QPointF(0.0, 2.0)); 0288 0289 t = QPointF(0.0, 1.0); 0290 b1 = QPointF(1.0, 0.0); 0291 b2 = QPointF(0.0, 1.0); 0292 result = KisAlgebra2D::transformAsBase(t, b1, b2); 0293 QCOMPARE(result, QPointF(-1.0, 0.0)); 0294 0295 t = QPointF(0.0, 1.0); 0296 b1 = QPointF(1.0, 0.0); 0297 b2 = QPointF(0.0, 2.0); 0298 result = KisAlgebra2D::transformAsBase(t, b1, b2); 0299 QCOMPARE(result, QPointF(-2.0, 0.0)); 0300 } 0301 0302 void KisCageTransformWorkerTest::testAngleBetweenVectors() 0303 { 0304 QPointF b1(1.0, 0.0); 0305 QPointF b2(2.0, 0.0); 0306 qreal result; 0307 0308 b1 = QPointF(1.0, 0.0); 0309 b2 = QPointF(0.0, 1.0); 0310 result = KisAlgebra2D::angleBetweenVectors(b1, b2); 0311 QCOMPARE(result, M_PI_2); 0312 0313 b1 = QPointF(1.0, 0.0); 0314 b2 = QPointF(std::sqrt(0.5), std::sqrt(0.5)); 0315 result = KisAlgebra2D::angleBetweenVectors(b1, b2); 0316 QCOMPARE(result, M_PI / 4); 0317 0318 QTransform t; 0319 t.rotateRadians(M_PI / 4); 0320 QCOMPARE(t.map(b1), b2); 0321 } 0322 0323 KISTEST_MAIN(KisCageTransformWorkerTest)