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" |