tests/auto/qpathclipper/tst_qpathclipper.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    38 ** $QT_END_LICENSE$
    38 ** $QT_END_LICENSE$
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 #include "private/qpathclipper_p.h"
    41 #include "private/qpathclipper_p.h"
    42 #include "paths.h"
    42 #include "paths.h"
       
    43 #include "pathcompare.h"
    43 
    44 
    44 #include <QtTest/QtTest>
    45 #include <QtTest/QtTest>
    45 
    46 
    46 #include <qpainterpath.h>
    47 #include <qpainterpath.h>
    47 #include <qpolygon.h>
    48 #include <qpolygon.h>
    92     void task204301_data();
    93     void task204301_data();
    93     void task204301();
    94     void task204301();
    94 
    95 
    95     void task209056();
    96     void task209056();
    96     void task251909();
    97     void task251909();
       
    98 
       
    99     void qtbug3778();
    97 };
   100 };
    98 
   101 
    99 Q_DECLARE_METATYPE(QPainterPath)
   102 Q_DECLARE_METATYPE(QPainterPath)
   100 Q_DECLARE_METATYPE(QPathClipper::Operation)
   103 Q_DECLARE_METATYPE(QPathClipper::Operation)
   101 
   104 
   280     path.lineTo(QPointF(511.42858, 426.64789));
   283     path.lineTo(QPointF(511.42858, 426.64789));
   281     path.lineTo(QPointF(511.42858, 446.6479));
   284     path.lineTo(QPointF(511.42858, 446.6479));
   282     return path;
   285     return path;
   283 }
   286 }
   284 
   287 
   285 static QPainterPath samplePath11()
       
   286 {
       
   287     QPainterPath path;
       
   288     path.moveTo(QPointF(165.71429, 338.79076));
       
   289     path.lineTo(QPointF(227.74288, 338.79076));
       
   290     path.cubicTo(QPointF(232.95048, 338.79076),
       
   291                  QPointF(237.14288, 342.88102),
       
   292                  QPointF(237.14288, 347.96176));
       
   293     path.lineTo(QPointF(237.14288, 366.76261));
       
   294     path.cubicTo(QPointF(237.14288, 371.84335),
       
   295                  QPointF(232.95048, 375.93361),
       
   296                  QPointF(227.74288, 375.93361));
       
   297     path.lineTo(QPointF(165.7142905131896, 375.93361));
       
   298     path.lineTo(QPointF(165.71429, 338.79076));
       
   299     return path;
       
   300 }
       
   301 static QPainterPath samplePath12()
       
   302 {
       
   303     QPainterPath path;
       
   304     path.moveTo(QPointF(333.297085225735, 61.53486494396167));
       
   305     path.cubicTo(QPointF(339.851755668807, 65.26555884471786),
       
   306                  QPointF(346.7164458828328, 69.04482864715078),
       
   307                  QPointF(353.4159970843586, 72.56059416636147));
       
   308     path.cubicTo(QPointF(353.4166971116034, 72.56155590850551),
       
   309                  QPointF(353.4173961086004, 72.56251809989483),
       
   310                  QPointF(353.4180950127331, 72.56348028832946));
       
   311     path.cubicTo(QPointF(342.4340366381152, 76.42344228577481),
       
   312                  QPointF(317.0596805768079, 94.67086588954379),
       
   313                  QPointF(309.78055, 101.00195));
       
   314     path.cubicTo(QPointF(286.0370715501102, 121.6530659984711),
       
   315                  QPointF(272.7748256344584, 134.1525788344904),
       
   316                  QPointF(250.7436468364447, 150.4434491585085));
       
   317     path.lineTo(QPointF(247.03629, 146.56585));
       
   318     path.lineTo(QPointF(240.71086, 91.501867));
       
   319     path.cubicTo(QPointF(240.71086, 91.501867),
       
   320                  QPointF(305.6382515924416, 62.21715375368672),
       
   321                  QPointF(333.297085225735, 61.53486494396167));
       
   322     return path;
       
   323 }
       
   324 
       
   325 static QPainterPath samplePath13()
   288 static QPainterPath samplePath13()
   326 {
   289 {
   327     QPainterPath path;
   290     QPainterPath path;
   328     path.moveTo(QPointF(160, 200));
   291     path.moveTo(QPointF(160, 200));
   329     path.lineTo(QPointF(100, 200));
   292     path.lineTo(QPointF(100, 200));
   334 }
   297 }
   335 
   298 
   336 static QPainterPath samplePath14()
   299 static QPainterPath samplePath14()
   337 {
   300 {
   338     QPainterPath path;
   301     QPainterPath path;
   339     path.moveTo(QPointF(100, 180));
   302 
   340     path.lineTo(QPointF(100, 80));
   303     path.moveTo(160, 80);
   341     path.lineTo(QPointF(120, 80));
   304     path.lineTo(160, 180);
   342     path.lineTo(QPointF(120, 100));
   305     path.lineTo(100, 180);
   343     path.lineTo(QPointF(160, 100));
   306     path.lineTo(100, 80);
   344     path.lineTo(QPointF(160, 180));
   307     path.lineTo(160, 80);
   345     path.lineTo(QPointF(100, 180));
   308     path.moveTo(160, 80);
       
   309     path.lineTo(160, 100);
       
   310     path.lineTo(120, 100);
       
   311     path.lineTo(120, 80);
       
   312 
   346     return path;
   313     return path;
   347 }
   314 }
   348 
   315 
   349 void tst_QPathClipper::clip_data()
   316 void tst_QPathClipper::clip_data()
   350 {
   317 {
   403     QTest::newRow( "simple10" )  << Paths::frame3()
   370     QTest::newRow( "simple10" )  << Paths::frame3()
   404                                  << Paths::frame4() * QTransform().translate(280, 220)
   371                                  << Paths::frame4() * QTransform().translate(280, 220)
   405                                  << QPathClipper::BoolAnd
   372                                  << QPathClipper::BoolAnd
   406                                  << samplePath10();
   373                                  << samplePath10();
   407 
   374 
   408     QTest::newRow( "simple11" )  << Paths::frame2()*QTransform().translate(40, 235)
       
   409                                  << Paths::frame1()
       
   410                                  << QPathClipper::BoolAnd
       
   411                                  << samplePath11();
       
   412 
       
   413     QTest::newRow( "intersection_at_edge" )  << Paths::lips()
       
   414                                              << Paths::mailbox()*QTransform().translate(-85, 34)
       
   415                                              << QPathClipper::BoolAnd
       
   416                                              << samplePath12();
       
   417 
       
   418     QTest::newRow( "simple_move_to1" )  << Paths::rect4()
   375     QTest::newRow( "simple_move_to1" )  << Paths::rect4()
   419                                        << Paths::rect2() * QTransform().translate(-20, 50)
   376                                        << Paths::rect2() * QTransform().translate(-20, 50)
   420                                        << QPathClipper::BoolAnd
   377                                        << QPathClipper::BoolAnd
   421                                        << samplePath13();
   378                                        << samplePath13();
   422 
   379 
   424                                         << Paths::rect2() * QTransform().translate(-20, 0)
   381                                         << Paths::rect2() * QTransform().translate(-20, 0)
   425                                         << QPathClipper::BoolAnd
   382                                         << QPathClipper::BoolAnd
   426                                         << samplePath14();
   383                                         << samplePath14();
   427 }
   384 }
   428 
   385 
   429 static const int precision = 8;
       
   430 static const qreal epsilon = pow(0.1, precision);
       
   431 
       
   432 static inline bool fuzzyIsZero(qreal x, qreal relative)
       
   433 {
       
   434     if (qAbs(relative) < epsilon)
       
   435         return qAbs(x) < epsilon;
       
   436     else
       
   437         return qAbs(x / relative) < epsilon;
       
   438 }
       
   439 
       
   440 static bool fuzzyCompare(const QPointF &a, const QPointF &b)
       
   441 {
       
   442     const QPointF delta = a - b;
       
   443 
       
   444     const qreal x = qMax(qAbs(a.x()), qAbs(b.x()));
       
   445     const qreal y = qMax(qAbs(a.y()), qAbs(b.y()));
       
   446 
       
   447     return fuzzyIsZero(delta.x(), x) && fuzzyIsZero(delta.y(), y);
       
   448 }
       
   449 
       
   450 static bool isClosed(const QPainterPath &path)
       
   451 {
       
   452     if (path.elementCount() == 0)
       
   453         return false;
       
   454 
       
   455     QPointF first = path.elementAt(0);
       
   456     QPointF last = path.elementAt(path.elementCount() - 1);
       
   457 
       
   458     return fuzzyCompare(first, last);
       
   459 }
       
   460 
       
   461 // rotation and direction independent path comparison
       
   462 // allows paths to be shifted or reversed relative to each other
       
   463 static bool comparePaths(const QPainterPath &actual, const QPainterPath &expected)
       
   464 {
       
   465     const int endActual = isClosed(actual) ? actual.elementCount() - 1 : actual.elementCount();
       
   466     const int endExpected = isClosed(expected) ? expected.elementCount() - 1 : expected.elementCount();
       
   467 
       
   468     if (endActual != endExpected)
       
   469         return false;
       
   470 
       
   471     for (int i = 0; i < endActual; ++i) {
       
   472         int k = 0;
       
   473         for (k = 0; k < endActual; ++k) {
       
   474             int i1 = k;
       
   475             int i2 = (i + k) % endActual;
       
   476 
       
   477             QPointF a = actual.elementAt(i1);
       
   478             QPointF b = expected.elementAt(i2);
       
   479 
       
   480             if (!fuzzyCompare(a, b))
       
   481                 break;
       
   482         }
       
   483 
       
   484         if (k == endActual)
       
   485             return true;
       
   486 
       
   487         for (k = 0; k < endActual; ++k) {
       
   488             int i1 = k;
       
   489             int i2 = (i + endActual - k) % endActual;
       
   490 
       
   491             QPointF a = actual.elementAt(i1);
       
   492             QPointF b = expected.elementAt(i2);
       
   493 
       
   494             if (!fuzzyCompare(a, b))
       
   495                 break;
       
   496         }
       
   497 
       
   498         if (k == endActual)
       
   499             return true;
       
   500     }
       
   501 
       
   502     return false;
       
   503 }
       
   504 
       
   505 // sanity check to make sure comparePaths declared above works
   386 // sanity check to make sure comparePaths declared above works
   506 void tst_QPathClipper::testComparePaths()
   387 void tst_QPathClipper::testComparePaths()
   507 {
   388 {
   508     QPainterPath a;
   389     QPainterPath a;
   509     QPainterPath b;
   390     QPainterPath b;
   510 
   391 
   511     a.addRect(0, 0, 10, 10);
   392     a.addRect(0, 0, 10, 10);
   512     b.addRect(0, 0, 10.00001, 10.00001);
   393     b.addRect(0, 0, 10.00001, 10.00001);
   513 
   394 
   514     QVERIFY(!comparePaths(a, b));
   395     QVERIFY(!QPathCompare::comparePaths(a, b));
   515 
   396 
   516     b = QPainterPath();
   397     b = QPainterPath();
   517     b.addRect(0, 0, 10.00000000001, 10.00000000001);
   398     b.addRect(0, 0, 10.00000000001, 10.00000000001);
   518 
   399 
   519     QVERIFY(comparePaths(a, b));
   400     QVERIFY(QPathCompare::comparePaths(a, b));
   520 
   401 
   521     b = QPainterPath();
   402     b = QPainterPath();
   522     b.moveTo(10, 0);
   403     b.moveTo(10, 0);
   523     b.lineTo(0, 0);
   404     b.lineTo(0, 0);
   524     b.lineTo(0, 10);
   405     b.lineTo(0, 10);
   525     b.lineTo(10, 10);
   406     b.lineTo(10, 10);
   526 
   407 
   527     QVERIFY(comparePaths(a, b));
   408     QVERIFY(QPathCompare::comparePaths(a, b));
   528     b.lineTo(10, 0);
   409     b.lineTo(10, 0);
   529     QVERIFY(comparePaths(a, b));
   410     QVERIFY(QPathCompare::comparePaths(a, b));
   530 
   411 
   531     b = QPainterPath();
   412     b = QPainterPath();
   532     b.moveTo(10, 0);
   413     b.moveTo(10, 0);
   533     b.lineTo(0, 10);
   414     b.lineTo(0, 10);
   534     b.lineTo(0, 0);
   415     b.lineTo(0, 0);
   535     b.lineTo(10, 10);
   416     b.lineTo(10, 10);
   536 
   417 
   537     QVERIFY(!comparePaths(a, b));
   418     QVERIFY(!QPathCompare::comparePaths(a, b));
   538 }
   419 }
   539 
   420 
   540 void tst_QPathClipper::clip()
   421 void tst_QPathClipper::clip()
   541 {
   422 {
   542     if (sizeof(double) != sizeof(qreal)) {
   423     if (sizeof(double) != sizeof(qreal)) {
   547     QFETCH( QPathClipper::Operation, op );
   428     QFETCH( QPathClipper::Operation, op );
   548     QFETCH( QPainterPath,  result);
   429     QFETCH( QPainterPath,  result);
   549     QPathClipper clipper(subject, clip);
   430     QPathClipper clipper(subject, clip);
   550     QPainterPath x = clipper.clip(op);
   431     QPainterPath x = clipper.clip(op);
   551 
   432 
   552     QVERIFY(comparePaths(x, result));
   433     QVERIFY(QPathCompare::comparePaths(x, result));
   553 }
   434 }
   554 
   435 
   555 static inline QPointF randomPointInRect(const QRectF &rect)
   436 static inline QPointF randomPointInRect(const QRectF &rect)
   556 {
   437 {
   557     qreal rx = qrand() / (RAND_MAX + 1.);
   438     qreal rx = qrand() / (RAND_MAX + 1.);
  1415     QPainterPath result = p1.united(p2);
  1296     QPainterPath result = p1.united(p2);
  1416 
  1297 
  1417     QVERIFY(result.elementCount() <= 5);
  1298     QVERIFY(result.elementCount() <= 5);
  1418 }
  1299 }
  1419 
  1300 
       
  1301 void tst_QPathClipper::qtbug3778()
       
  1302 {
       
  1303     QPainterPath path1;
       
  1304     path1.moveTo(200, 3.22409e-5);
       
  1305     // e-5 and higher leads to a bug
       
  1306     // Using 3.22409e-4 starts to work correctly
       
  1307     path1.lineTo(0, 0);
       
  1308     path1.lineTo(1.07025e-13, 1450);
       
  1309     path1.lineTo(750, 950);
       
  1310     path1.lineTo(950, 750);
       
  1311     path1.lineTo(200, 3.22409e-13);
       
  1312 
       
  1313     QPainterPath path2;
       
  1314     path2.moveTo(0, 0);
       
  1315     path2.lineTo(200, 800);
       
  1316     path2.lineTo(600, 1500);
       
  1317     path2.lineTo(1500, 1400);
       
  1318     path2.lineTo(1900, 1200);
       
  1319     path2.lineTo(2000, 1000);
       
  1320     path2.lineTo(1400, 0);
       
  1321     path2.lineTo(0, 0);
       
  1322 
       
  1323     QPainterPath p12 = path1.intersected(path2);
       
  1324 
       
  1325     QVERIFY(p12.contains(QPointF(100, 100)));
       
  1326 }
       
  1327 
  1420 QTEST_APPLESS_MAIN(tst_QPathClipper)
  1328 QTEST_APPLESS_MAIN(tst_QPathClipper)
  1421 
  1329 
  1422 
  1330 
  1423 #include "tst_qpathclipper.moc"
  1331 #include "tst_qpathclipper.moc"