Changeset 846 for trunk/src/gui/painting/qpathclipper.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/gui/painting/qpathclipper.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 44 44 #include <private/qbezier_p.h> 45 45 #include <private/qdatabuffer_p.h> 46 #include <private/qnumeric_p.h> 46 47 #include <qmath.h> 47 48 … … 86 87 } 87 88 88 static QPointF normalize(const QPointF &p) 89 { 90 return p / qSqrt(p.x() * p.x() + p.y() * p.y()); 89 static void normalize(double &x, double &y) 90 { 91 double reciprocal = 1 / qSqrt(x * x + y * y); 92 x *= reciprocal; 93 y *= reciprocal; 91 94 } 92 95 … … 106 109 107 110 private: 108 void intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections);109 void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections);110 111 bool beziersIntersect(const QBezier &one, const QBezier &two) const;112 111 bool linesIntersect(const QLineF &a, const QLineF &b) const; 113 112 }; 114 115 bool QIntersectionFinder::beziersIntersect(const QBezier &one, const QBezier &two) const116 {117 return (comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2())118 && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4()))119 || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3())120 && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))121 || QBezier::findIntersections(one, two, 0);122 }123 113 124 114 bool QIntersectionFinder::linesIntersect(const QLineF &a, const QLineF &b) const … … 175 165 } 176 166 177 // if the lines are not parallel and share a common end point, then they178 // don't intersect179 if (p1_equals_q1 || p1_equals_q2 || p2_equals_q1 || p2_equals_q2)180 return false;181 182 167 const qreal invPar = 1 / par; 183 168 … … 194 179 } 195 180 196 void QIntersectionFinder::intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections) 197 { 198 if ((comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2()) 199 && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4())) 200 || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3()) 201 && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))) { 202 203 return; 204 } 205 206 t.clear(); 207 208 if (!QBezier::findIntersections(one, two, &t)) 209 return; 210 211 int count = t.size(); 212 213 for (int i = 0; i < count; ++i) { 214 qreal alpha_p = t.at(i).first; 215 qreal alpha_q = t.at(i).second; 216 217 QPointF pt; 218 if (qFuzzyIsNull(alpha_p)) { 219 pt = one.pt1(); 220 } else if (qFuzzyIsNull(alpha_p - 1)) { 221 pt = one.pt4(); 222 } else if (qFuzzyIsNull(alpha_q)) { 223 pt = two.pt1(); 224 } else if (qFuzzyIsNull(alpha_q - 1)) { 225 pt = two.pt4(); 181 bool QIntersectionFinder::hasIntersections(const QPathSegments &a, const QPathSegments &b) const 182 { 183 if (a.segments() == 0 || b.segments() == 0) 184 return false; 185 186 const QRectF &rb0 = b.elementBounds(0); 187 188 qreal minX = rb0.left(); 189 qreal minY = rb0.top(); 190 qreal maxX = rb0.right(); 191 qreal maxY = rb0.bottom(); 192 193 for (int i = 1; i < b.segments(); ++i) { 194 const QRectF &r = b.elementBounds(i); 195 minX = qMin(minX, r.left()); 196 minY = qMin(minY, r.top()); 197 maxX = qMax(maxX, r.right()); 198 maxY = qMax(maxY, r.bottom()); 199 } 200 201 QRectF rb(minX, minY, maxX - minX, maxY - minY); 202 203 for (int i = 0; i < a.segments(); ++i) { 204 const QRectF &r1 = a.elementBounds(i); 205 206 if (r1.left() > rb.right() || rb.left() > r1.right()) 207 continue; 208 if (r1.top() > rb.bottom() || rb.top() > r1.bottom()) 209 continue; 210 211 for (int j = 0; j < b.segments(); ++j) { 212 const QRectF &r2 = b.elementBounds(j); 213 214 if (r1.left() > r2.right() || r2.left() > r1.right()) 215 continue; 216 if (r1.top() > r2.bottom() || r2.top() > r1.bottom()) 217 continue; 218 219 if (linesIntersect(a.lineAt(i), b.lineAt(j))) 220 return true; 221 } 222 } 223 224 return false; 225 } 226 227 namespace { 228 struct TreeNode 229 { 230 qreal splitLeft; 231 qreal splitRight; 232 bool leaf; 233 234 int lowestLeftIndex; 235 int lowestRightIndex; 236 237 union { 238 struct { 239 int first; 240 int last; 241 } interval; 242 struct { 243 int left; 244 int right; 245 } children; 246 } index; 247 }; 248 249 struct RectF 250 { 251 qreal x1; 252 qreal y1; 253 qreal x2; 254 qreal y2; 255 }; 256 257 class SegmentTree 258 { 259 public: 260 SegmentTree(QPathSegments &segments); 261 262 QRectF boundingRect() const; 263 264 void produceIntersections(int segment); 265 266 private: 267 TreeNode buildTree(int first, int last, int depth, const RectF &bounds); 268 269 void produceIntersectionsLeaf(const TreeNode &node, int segment); 270 void produceIntersections(const TreeNode &node, int segment, const RectF &segmentBounds, const RectF &nodeBounds, int axis); 271 void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections); 272 273 QPathSegments &m_segments; 274 QVector<int> m_index; 275 276 RectF m_bounds; 277 278 QVector<TreeNode> m_tree; 279 QDataBuffer<QIntersection> m_intersections; 280 }; 281 282 SegmentTree::SegmentTree(QPathSegments &segments) 283 : m_segments(segments), 284 m_intersections(0) 285 { 286 m_bounds.x1 = qt_inf(); 287 m_bounds.y1 = qt_inf(); 288 m_bounds.x2 = -qt_inf(); 289 m_bounds.y2 = -qt_inf(); 290 291 m_index.resize(m_segments.segments()); 292 293 for (int i = 0; i < m_index.size(); ++i) { 294 m_index[i] = i; 295 296 const QRectF &segmentBounds = m_segments.elementBounds(i); 297 298 if (segmentBounds.left() < m_bounds.x1) 299 m_bounds.x1 = segmentBounds.left(); 300 if (segmentBounds.top() < m_bounds.y1) 301 m_bounds.y1 = segmentBounds.top(); 302 if (segmentBounds.right() > m_bounds.x2) 303 m_bounds.x2 = segmentBounds.right(); 304 if (segmentBounds.bottom() > m_bounds.y2) 305 m_bounds.y2 = segmentBounds.bottom(); 306 } 307 308 m_tree.resize(1); 309 310 TreeNode root = buildTree(0, m_index.size(), 0, m_bounds); 311 m_tree[0] = root; 312 } 313 314 QRectF SegmentTree::boundingRect() const 315 { 316 return QRectF(QPointF(m_bounds.x1, m_bounds.y1), 317 QPointF(m_bounds.x2, m_bounds.y2)); 318 } 319 320 static inline qreal coordinate(const QPointF &pos, int axis) 321 { 322 return axis == 0 ? pos.x() : pos.y(); 323 } 324 325 TreeNode SegmentTree::buildTree(int first, int last, int depth, const RectF &bounds) 326 { 327 if (depth >= 24 || (last - first) <= 10) { 328 TreeNode node; 329 node.leaf = true; 330 node.index.interval.first = first; 331 node.index.interval.last = last; 332 333 return node; 334 } 335 336 int splitAxis = (depth & 1); 337 338 TreeNode node; 339 node.leaf = false; 340 341 qreal split = 0.5f * ((&bounds.x1)[splitAxis] + (&bounds.x2)[splitAxis]); 342 343 node.splitLeft = (&bounds.x1)[splitAxis]; 344 node.splitRight = (&bounds.x2)[splitAxis]; 345 346 node.lowestLeftIndex = INT_MAX; 347 node.lowestRightIndex = INT_MAX; 348 349 const int treeSize = m_tree.size(); 350 351 node.index.children.left = treeSize; 352 node.index.children.right = treeSize + 1; 353 354 m_tree.resize(treeSize + 2); 355 356 int l = first; 357 int r = last - 1; 358 359 // partition into left and right sets 360 while (l <= r) { 361 const int index = m_index.at(l); 362 const QRectF &segmentBounds = m_segments.elementBounds(index); 363 364 qreal lowCoordinate = coordinate(segmentBounds.topLeft(), splitAxis); 365 366 if (coordinate(segmentBounds.center(), splitAxis) < split) { 367 qreal highCoordinate = coordinate(segmentBounds.bottomRight(), splitAxis); 368 if (highCoordinate > node.splitLeft) 369 node.splitLeft = highCoordinate; 370 if (index < node.lowestLeftIndex) 371 node.lowestLeftIndex = index; 372 ++l; 226 373 } else { 227 pt = one.pointAt(alpha_p); 228 } 229 230 QIntersection intersection; 231 intersection.alphaA = alpha_p; 232 intersection.alphaB = alpha_q; 233 intersection.pos = pt; 234 intersections.add(intersection); 235 } 236 } 237 238 void QIntersectionFinder::intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections) 374 if (lowCoordinate < node.splitRight) 375 node.splitRight = lowCoordinate; 376 if (index < node.lowestRightIndex) 377 node.lowestRightIndex = index; 378 qSwap(m_index[l], m_index[r]); 379 --r; 380 } 381 } 382 383 RectF lbounds = bounds; 384 (&lbounds.x2)[splitAxis] = node.splitLeft; 385 386 RectF rbounds = bounds; 387 (&rbounds.x1)[splitAxis] = node.splitRight; 388 389 TreeNode left = buildTree(first, l, depth + 1, lbounds); 390 m_tree[node.index.children.left] = left; 391 392 TreeNode right = buildTree(l, last, depth + 1, rbounds); 393 m_tree[node.index.children.right] = right; 394 395 return node; 396 } 397 398 void SegmentTree::intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections) 239 399 { 240 400 const QPointF p1 = a.p1(); … … 358 518 } 359 519 360 static const QBezier bezierFromLine(const QLineF &line) 361 { 362 const QPointF p1 = line.p1(); 363 const QPointF p2 = line.p2(); 364 const QPointF delta = (p2 - p1) / 3; 365 return QBezier::fromPoints(p1, p1 + delta, p1 + 2 * delta, p2); 366 } 367 368 bool QIntersectionFinder::hasIntersections(const QPathSegments &a, const QPathSegments &b) const 369 { 370 QBezier tempA; 371 QBezier tempB; 372 373 if (a.segments() == 0 || b.segments() == 0) 374 return false; 375 376 const QRectF &rb0 = b.elementBounds(0); 377 378 qreal minX = rb0.left(); 379 qreal minY = rb0.top(); 380 qreal maxX = rb0.right(); 381 qreal maxY = rb0.bottom(); 382 383 for (int i = 1; i < b.segments(); ++i) { 384 const QRectF &r = b.elementBounds(i); 385 minX = qMin(minX, r.left()); 386 minY = qMin(minY, r.top()); 387 maxX = qMax(maxX, r.right()); 388 maxY = qMax(maxY, r.bottom()); 389 } 390 391 QRectF rb(minX, minY, maxX - minX, maxY - minY); 392 393 for (int i = 0; i < a.segments(); ++i) { 394 const QBezier *bezierA = a.bezierAt(i); 395 bool isBezierA = bezierA != 0; 396 397 const QRectF &r1 = a.elementBounds(i); 398 399 if (r1.left() > rb.right() || rb.left() > r1.right()) 520 void SegmentTree::produceIntersections(int segment) 521 { 522 const QRectF &segmentBounds = m_segments.elementBounds(segment); 523 524 RectF sbounds; 525 sbounds.x1 = segmentBounds.left(); 526 sbounds.y1 = segmentBounds.top(); 527 sbounds.x2 = segmentBounds.right(); 528 sbounds.y2 = segmentBounds.bottom(); 529 530 produceIntersections(m_tree.at(0), segment, sbounds, m_bounds, 0); 531 } 532 533 void SegmentTree::produceIntersectionsLeaf(const TreeNode &node, int segment) 534 { 535 const QRectF &r1 = m_segments.elementBounds(segment); 536 const QLineF lineA = m_segments.lineAt(segment); 537 538 for (int i = node.index.interval.first; i < node.index.interval.last; ++i) { 539 const int other = m_index.at(i); 540 if (other >= segment) 400 541 continue; 401 if (r1.top() > rb.bottom() || rb.top() > r1.bottom()) 542 543 const QRectF &r2 = m_segments.elementBounds(other); 544 545 if (r1.left() > r2.right() || r2.left() > r1.right()) 402 546 continue; 403 404 for (int j = 0; j < b.segments(); ++j) { 405 const QRectF &r2 = b.elementBounds(j); 406 407 if (r1.left() > r2.right() || r2.left() > r1.right()) 408 continue; 409 if (r1.top() > r2.bottom() || r2.top() > r1.bottom()) 410 continue; 411 412 bool isBezierB = b.bezierAt(j) != 0; 413 414 if (isBezierA || isBezierB) { 415 const QBezier *bezierB; 416 if (isBezierB) { 417 bezierB = b.bezierAt(j); 418 } else { 419 tempB = bezierFromLine(b.lineAt(j)); 420 bezierB = &tempB; 421 } 422 423 if (!bezierA) { 424 tempA = bezierFromLine(a.lineAt(i)); 425 bezierA = &tempA; 426 } 427 428 if (beziersIntersect(*bezierA, *bezierB)) 429 return true; 430 } else { 431 if (linesIntersect(a.lineAt(i), b.lineAt(j))) 432 return true; 433 } 434 } 435 } 436 437 return false; 547 if (r1.top() > r2.bottom() || r2.top() > r1.bottom()) 548 continue; 549 550 m_intersections.reset(); 551 552 const QLineF lineB = m_segments.lineAt(other); 553 554 intersectLines(lineA, lineB, m_intersections); 555 556 for (int k = 0; k < m_intersections.size(); ++k) { 557 QPathSegments::Intersection i_isect, j_isect; 558 i_isect.vertex = j_isect.vertex = m_segments.addPoint(m_intersections.at(k).pos); 559 560 i_isect.t = m_intersections.at(k).alphaA; 561 j_isect.t = m_intersections.at(k).alphaB; 562 563 i_isect.next = 0; 564 j_isect.next = 0; 565 566 m_segments.addIntersection(segment, i_isect); 567 m_segments.addIntersection(other, j_isect); 568 } 569 } 570 } 571 572 void SegmentTree::produceIntersections(const TreeNode &node, int segment, const RectF &segmentBounds, const RectF &nodeBounds, int axis) 573 { 574 if (node.leaf) { 575 produceIntersectionsLeaf(node, segment); 576 return; 577 } 578 579 RectF lbounds = nodeBounds; 580 (&lbounds.x2)[axis] = node.splitLeft; 581 582 RectF rbounds = nodeBounds; 583 (&rbounds.x1)[axis] = node.splitRight; 584 585 if (segment > node.lowestLeftIndex && (&segmentBounds.x1)[axis] <= node.splitLeft) 586 produceIntersections(m_tree.at(node.index.children.left), segment, segmentBounds, lbounds, !axis); 587 588 if (segment > node.lowestRightIndex && (&segmentBounds.x2)[axis] >= node.splitRight) 589 produceIntersections(m_tree.at(node.index.children.right), segment, segmentBounds, rbounds, !axis); 590 } 591 438 592 } 439 593 440 594 void QIntersectionFinder::produceIntersections(QPathSegments &segments) 441 595 { 442 QBezier tempA; 443 QBezier tempB; 444 445 QVector<QPair<qreal, qreal> > t; 446 QDataBuffer<QIntersection> intersections; 447 448 for (int i = 0; i < segments.segments(); ++i) { 449 const QBezier *bezierA = segments.bezierAt(i); 450 bool isBezierA = bezierA != 0; 451 452 const QRectF &r1 = segments.elementBounds(i); 453 454 for (int j = 0; j < i; ++j) { 455 const QRectF &r2 = segments.elementBounds(j); 456 457 if (r1.left() > r2.right() || r2.left() > r1.right()) 458 continue; 459 if (r1.top() > r2.bottom() || r2.top() > r1.bottom()) 460 continue; 461 462 intersections.reset(); 463 464 bool isBezierB = segments.bezierAt(j) != 0; 465 466 if (isBezierA || isBezierB) { 467 const QBezier *bezierB; 468 if (isBezierB) { 469 bezierB = segments.bezierAt(j); 470 } else { 471 tempB = bezierFromLine(segments.lineAt(j)); 472 bezierB = &tempB; 473 } 474 475 if (!bezierA) { 476 tempA = bezierFromLine(segments.lineAt(i)); 477 bezierA = &tempA; 478 } 479 480 intersectBeziers(*bezierA, *bezierB, t, intersections); 481 } else { 482 const QLineF lineA = segments.lineAt(i); 483 const QLineF lineB = segments.lineAt(j); 484 485 intersectLines(lineA, lineB, intersections); 486 } 487 488 for (int k = 0; k < intersections.size(); ++k) { 489 QPathSegments::Intersection i_isect, j_isect; 490 i_isect.vertex = j_isect.vertex = segments.addPoint(intersections.at(k).pos); 491 492 i_isect.t = intersections.at(k).alphaA; 493 j_isect.t = intersections.at(k).alphaB; 494 495 i_isect.next = 0; 496 j_isect.next = 0; 497 498 segments.addIntersection(i, i_isect); 499 segments.addIntersection(j, j_isect); 500 } 501 } 502 } 596 SegmentTree tree(segments); 597 598 for (int i = 0; i < segments.segments(); ++i) 599 tree.produceIntersections(i); 503 600 } 504 601 … … 713 810 addVertex(m_segments.pointAt(i)); 714 811 715 QDataBuffer<QPathSegments::Intersection> intersections ;812 QDataBuffer<QPathSegments::Intersection> intersections(m_segments.segments()); 716 813 for (int i = 0; i < m_segments.segments(); ++i) { 717 814 intersections.reset(); … … 732 829 qSort(intersections.data(), intersections.data() + intersections.size()); 733 830 734 const QBezier *bezier = m_segments.bezierAt(i); 735 if (bezier) { 736 int first = m_segments.segmentAt(i).va; 737 int second = m_segments.segmentAt(i).vb; 738 739 qreal alpha = 0.0; 740 int last = first; 741 for (int j = 0; j < intersections.size(); ++j) { 742 const QPathSegments::Intersection &isect = intersections.at(j); 743 744 addBezierEdge(bezier, last, isect.vertex, alpha, isect.t, pathId); 745 746 alpha = isect.t; 747 last = isect.vertex; 748 } 749 750 addBezierEdge(bezier, last, second, alpha, 1.0, pathId); 751 } else { 752 int first = m_segments.segmentAt(i).va; 753 int second = m_segments.segmentAt(i).vb; 754 755 int last = first; 756 for (int j = 0; j < intersections.size(); ++j) { 757 const QPathSegments::Intersection &isect = intersections.at(j); 758 759 QPathEdge *ep = edge(addEdge(last, isect.vertex)); 760 761 if (ep) { 762 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(isect.vertex).y() ? 1 : -1; 763 if (pathId == 0) 764 ep->windingA += dir; 765 else 766 ep->windingB += dir; 767 } 768 769 last = isect.vertex; 770 } 771 772 QPathEdge *ep = edge(addEdge(last, second)); 831 int first = m_segments.segmentAt(i).va; 832 int second = m_segments.segmentAt(i).vb; 833 834 int last = first; 835 for (int j = 0; j < intersections.size(); ++j) { 836 const QPathSegments::Intersection &isect = intersections.at(j); 837 838 QPathEdge *ep = edge(addEdge(last, isect.vertex)); 773 839 774 840 if (ep) { 775 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt( second).y() ? 1 : -1;841 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(isect.vertex).y() ? 1 : -1; 776 842 if (pathId == 0) 777 843 ep->windingA += dir; … … 779 845 ep->windingB += dir; 780 846 } 781 } 782 } 783 } 784 785 QWingedEdge::QWingedEdge() 786 { 787 } 788 789 QWingedEdge::QWingedEdge(const QPainterPath &subject, const QPainterPath &clip) 847 848 last = isect.vertex; 849 } 850 851 QPathEdge *ep = edge(addEdge(last, second)); 852 853 if (ep) { 854 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(second).y() ? 1 : -1; 855 if (pathId == 0) 856 ep->windingA += dir; 857 else 858 ep->windingB += dir; 859 } 860 } 861 } 862 863 QWingedEdge::QWingedEdge() : 864 m_edges(0), 865 m_vertices(0), 866 m_segments(0) 867 { 868 } 869 870 QWingedEdge::QWingedEdge(const QPainterPath &subject, const QPainterPath &clip) : 871 m_edges(subject.elementCount()), 872 m_vertices(subject.elementCount()), 873 m_segments(subject.elementCount()) 790 874 { 791 875 m_segments.setPath(subject); … … 833 917 { 834 918 m_points.reset(); 835 m_beziers.reset();836 919 m_intersections.reset(); 837 920 m_segments.reset(); … … 880 963 m_segments << Segment(m_pathId, last, current); 881 964 } else { 882 m_segments << Segment(m_pathId, last, current, m_beziers.size()); 883 m_beziers << bezier; 965 QRectF bounds = bezier.bounds(); 966 967 // threshold based on similar algorithm as in qtriangulatingstroker.cpp 968 int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * (2 * qreal(3.14) / 6)); 969 970 if (threshold < 3) threshold = 3; 971 qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1); 972 973 for (int t = 1; t < threshold - 1; ++t) { 974 currentPoint = bezier.pointAt(t * one_over_threshold_minus_1); 975 976 int index = m_points.size(); 977 m_segments << Segment(m_pathId, last, index); 978 last = index; 979 980 m_points << currentPoint; 981 } 982 983 m_segments << Segment(m_pathId, last, current); 884 984 } 885 985 } … … 897 997 898 998 for (int i = firstSegment; i < m_segments.size(); ++i) { 899 const QBezier *bezier = bezierAt(i); 900 if (bezier) { 901 m_segments.at(i).bounds = bezier->bounds(); 902 } else { 903 const QLineF line = lineAt(i); 904 905 qreal x1 = line.p1().x(); 906 qreal y1 = line.p1().y(); 907 qreal x2 = line.p2().x(); 908 qreal y2 = line.p2().y(); 909 910 if (x2 < x1) 911 qSwap(x1, x2); 912 if (y2 < y1) 913 qSwap(y1, y2); 914 915 m_segments.at(i).bounds = QRectF(x1, y1, x2 - x1, y2 - y1); 916 } 999 const QLineF line = lineAt(i); 1000 1001 qreal x1 = line.p1().x(); 1002 qreal y1 = line.p1().y(); 1003 qreal x2 = line.p2().x(); 1004 qreal y2 = line.p2().y(); 1005 1006 if (x2 < x1) 1007 qSwap(x1, x2); 1008 if (y2 < y1) 1009 qSwap(y1, y2); 1010 1011 m_segments.at(i).bounds = QRectF(x1, y1, x2 - x1, y2 - y1); 917 1012 } 918 1013 … … 925 1020 const QPathEdge *bp = edge(b); 926 1021 927 qreala_angle = ap->angle;928 qrealb_angle = bp->angle;1022 double a_angle = ap->angle; 1023 double b_angle = bp->angle; 929 1024 930 1025 if (vertex == ap->second) … … 934 1029 b_angle = bp->invAngle; 935 1030 936 qreal result = b_angle - a_angle; 937 938 if (qFuzzyIsNull(result) || qFuzzyCompare(result, 128)) 939 return 0; 940 941 if (result < 0) 1031 double result = b_angle - a_angle; 1032 1033 if (result >= 128.) 1034 return result - 128.; 1035 else if (result < 0) 942 1036 return result + 128.; 943 1037 else … … 945 1039 } 946 1040 947 static inline QPointF tangentAt(const QWingedEdge &list, int vi, int ei)1041 static inline QPointF midPoint(const QWingedEdge &list, int ei) 948 1042 { 949 1043 const QPathEdge *ep = list.edge(ei); 950 1044 Q_ASSERT(ep); 951 1045 952 qreal t; 953 qreal sign; 954 955 if (ep->first == vi) { 956 t = ep->t0; 957 sign = 1; 958 } else { 959 t = ep->t1; 960 sign = -1; 961 } 962 963 QPointF normal; 964 if (ep->bezier) { 965 normal = ep->bezier->derivedAt(t); 966 967 if (qFuzzyIsNull(normal.x()) && qFuzzyIsNull(normal.y())) 968 normal = ep->bezier->secondDerivedAt(t); 969 } else { 970 const QPointF a = *list.vertex(ep->first); 971 const QPointF b = *list.vertex(ep->second); 972 normal = b - a; 973 } 974 975 return normalize(sign * normal); 976 } 977 978 static inline QPointF midPoint(const QWingedEdge &list, int ei) 979 { 980 const QPathEdge *ep = list.edge(ei); 981 Q_ASSERT(ep); 982 983 if (ep->bezier) { 984 return ep->bezier->pointAt(0.5 * (ep->t0 + ep->t1)); 985 } else { 986 const QPointF a = *list.vertex(ep->first); 987 const QPointF b = *list.vertex(ep->second); 988 return a + 0.5 * (b - a); 989 } 990 } 991 992 static QBezier transform(const QBezier &bezier, const QPointF &xAxis, const QPointF &yAxis, const QPointF &origin) 993 { 994 QPointF points[4] = { 995 bezier.pt1(), 996 bezier.pt2(), 997 bezier.pt3(), 998 bezier.pt4() 999 }; 1000 1001 for (int i = 0; i < 4; ++i) { 1002 const QPointF p = points[i] - origin; 1003 1004 points[i].rx() = dot(xAxis, p); 1005 points[i].ry() = dot(yAxis, p); 1006 } 1007 1008 return QBezier::fromPoints(points[0], points[1], points[2], points[3]); 1009 } 1010 1011 static bool isLeftOf(const QWingedEdge &list, int vi, int ai, int bi) 1012 { 1013 const QPathEdge *ap = list.edge(ai); 1014 const QPathEdge *bp = list.edge(bi); 1015 1016 Q_ASSERT(ap); 1017 Q_ASSERT(bp); 1018 1019 if (!(ap->bezier || bp->bezier)) 1020 return false; 1021 1022 const QPointF tangent = tangentAt(list, vi, ai); 1023 const QPointF normal(tangent.y(), -tangent.x()); 1024 1025 const QPointF origin = *list.vertex(vi); 1026 1027 const QPointF dpA = midPoint(list, ai) - origin; 1028 const QPointF dpB = midPoint(list, bi) - origin; 1029 1030 qreal xA = dot(normal, dpA); 1031 qreal xB = dot(normal, dpB); 1032 1033 if (xA <= 0 && xB >= 0) 1034 return true; 1035 1036 if (xA >= 0 && xB <= 0) 1037 return false; 1038 1039 if (!ap->bezier) 1040 return xB > 0; 1041 1042 if (!bp->bezier) 1043 return xA < 0; 1044 1045 // both are beziers on the same side of the tangent 1046 1047 // transform the beziers into the local coordinate system 1048 // such that positive y is along the tangent, and positive x is along the normal 1049 1050 QBezier bezierA = transform(*ap->bezier, normal, tangent, origin); 1051 QBezier bezierB = transform(*bp->bezier, normal, tangent, origin); 1052 1053 qreal y = qMin(bezierA.pointAt(0.5 * (ap->t0 + ap->t1)).y(), 1054 bezierB.pointAt(0.5 * (bp->t0 + bp->t1)).y()); 1055 1056 xA = bezierA.pointAt(bezierA.tForY(ap->t0, ap->t1, y)).x(); 1057 xB = bezierB.pointAt(bezierB.tForY(bp->t0, bp->t1, y)).x(); 1058 1059 return xA < xB; 1046 const QPointF a = *list.vertex(ep->first); 1047 const QPointF b = *list.vertex(ep->second); 1048 return a + 0.5 * (b - a); 1060 1049 } 1061 1050 … … 1086 1075 1087 1076 Q_ASSERT(edge(status.edge)->vertex(status.direction) == vi); 1088 1089 1077 qreal d2 = delta(vi, ei, status.edge); 1090 1078 … … 1094 1082 #endif 1095 1083 1096 if (!(qFuzzyIsNull(d2) && isLeftOf(*this, vi, status.edge, ei)) 1097 && (d2 < d || (qFuzzyCompare(d2, d) && isLeftOf(*this, vi, status.edge, position)))) { 1084 if (d2 < d) { 1098 1085 position = status.edge; 1099 1086 d = d2; … … 1187 1174 } 1188 1175 1189 static qrealcomputeAngle(const QPointF &v)1176 static double computeAngle(const QPointF &v) 1190 1177 { 1191 1178 #if 1 … … 1196 1183 } 1197 1184 1198 QPointF nv = normalize(v); 1199 if (nv.y() < 0) { 1200 if (nv.x() < 0) { // 0 - 32 1201 return -32. * nv.x(); 1185 double vx = v.x(); 1186 double vy = v.y(); 1187 normalize(vx, vy); 1188 if (vy < 0) { 1189 if (vx < 0) { // 0 - 32 1190 return -32. * vx; 1202 1191 } else { // 96 - 128 1203 return 128. - 32. * nv.x();1192 return 128. - 32. * vx; 1204 1193 } 1205 1194 } else { // 32 - 96 1206 return 64. + 32 * nv.x();1195 return 64. + 32. * vx; 1207 1196 } 1208 1197 #else … … 1212 1201 } 1213 1202 1214 int QWingedEdge::addEdge(const QPointF &a, const QPointF &b , const QBezier *bezier, qreal t0, qreal t1)1203 int QWingedEdge::addEdge(const QPointF &a, const QPointF &b) 1215 1204 { 1216 1205 int fi = insert(a); 1217 1206 int si = insert(b); 1218 1207 1219 return addEdge(fi, si , bezier, t0, t1);1220 } 1221 1222 int QWingedEdge::addEdge(int fi, int si , const QBezier *bezier, qreal t0, qreal t1)1208 return addEdge(fi, si); 1209 } 1210 1211 int QWingedEdge::addEdge(int fi, int si) 1223 1212 { 1224 1213 if (fi == si) … … 1238 1227 QPathEdge *ep = edge(ei); 1239 1228 1240 ep->bezier = bezier; 1241 ep->t0 = t0; 1242 ep->t1 = t1; 1243 1244 if (bezier) { 1245 QPointF aTangent = bezier->derivedAt(t0); 1246 QPointF bTangent = -bezier->derivedAt(t1); 1247 1248 if (qFuzzyIsNull(aTangent.x()) && qFuzzyIsNull(aTangent.y())) 1249 aTangent = bezier->secondDerivedAt(t0); 1250 1251 if (qFuzzyIsNull(bTangent.x()) && qFuzzyIsNull(bTangent.y())) 1252 bTangent = bezier->secondDerivedAt(t1); 1253 1254 ep->angle = computeAngle(aTangent); 1255 ep->invAngle = computeAngle(bTangent); 1256 } else { 1257 const QPointF tangent = QPointF(*sp) - QPointF(*fp); 1258 ep->angle = computeAngle(tangent); 1259 ep->invAngle = ep->angle + 64; 1260 if (ep->invAngle >= 128) 1261 ep->invAngle -= 128; 1262 } 1229 const QPointF tangent = QPointF(*sp) - QPointF(*fp); 1230 ep->angle = computeAngle(tangent); 1231 ep->invAngle = ep->angle + 64; 1232 if (ep->invAngle >= 128) 1233 ep->invAngle -= 128; 1263 1234 1264 1235 QPathVertex *vertices[2] = { fp, sp }; … … 1315 1286 } 1316 1287 1317 void QWingedEdge::addBezierEdge(const QBezier *bezier, int vertexA, int vertexB, qreal alphaA, qreal alphaB, int path)1318 {1319 if (qFuzzyCompare(alphaA, alphaB))1320 return;1321 1322 qreal alphaMid = (alphaA + alphaB) * 0.5;1323 1324 qreal s0 = 0;1325 qreal s1 = 1;1326 int count = bezier->stationaryYPoints(s0, s1);1327 1328 m_splitPoints.clear();1329 m_splitPoints << alphaA;1330 m_splitPoints << alphaMid;1331 m_splitPoints << alphaB;1332 1333 if (count > 0 && !qFuzzyCompare(s0, alphaA) && !qFuzzyCompare(s0, alphaMid) && !qFuzzyCompare(s0, alphaB) && s0 > alphaA && s0 < alphaB)1334 m_splitPoints << s0;1335 1336 if (count > 1 && !qFuzzyCompare(s1, alphaA) && !qFuzzyCompare(s1, alphaMid) && !qFuzzyCompare(s1, alphaB) && s1 > alphaA && s1 < alphaB)1337 m_splitPoints << s1;1338 1339 if (count > 0)1340 qSort(m_splitPoints.begin(), m_splitPoints.end());1341 1342 int last = vertexA;1343 for (int i = 0; i < m_splitPoints.size() - 1; ++i) {1344 const qreal t0 = m_splitPoints[i];1345 const qreal t1 = m_splitPoints[i+1];1346 1347 int current;1348 if ((i + 1) == (m_splitPoints.size() - 1)) {1349 current = vertexB;1350 } else {1351 current = insert(bezier->pointAt(t1));1352 }1353 1354 QPathEdge *ep = edge(addEdge(last, current, bezier, t0, t1));1355 1356 if (ep) {1357 const int dir = m_vertices.at(last).y < m_vertices.at(current).y ? 1 : -1;1358 if (path == 0)1359 ep->windingA += dir;1360 else1361 ep->windingB += dir;1362 }1363 1364 last = current;1365 }1366 }1367 1368 void QWingedEdge::addBezierEdge(const QBezier *bezier, const QPointF &a, const QPointF &b, qreal alphaA, qreal alphaB, int path)1369 {1370 if (qFuzzyCompare(alphaA, alphaB))1371 return;1372 1373 if (comparePoints(a, b)) {1374 int v = insert(a);1375 1376 addBezierEdge(bezier, v, v, alphaA, alphaB, path);1377 } else {1378 int va = insert(a);1379 int vb = insert(b);1380 1381 addBezierEdge(bezier, va, vb, alphaA, alphaB, path);1382 }1383 }1384 1385 1288 int QWingedEdge::insert(const QPathVertex &vertex) 1386 1289 { … … 1431 1334 status.direction = QPathEdge::Forward; 1432 1335 1433 const QBezier *bezier = 0;1434 qreal t0 = 1;1435 qreal t1 = 0;1436 bool forward = true;1437 1438 1336 path.moveTo(*list.vertex(list.edge(edge)->first)); 1439 1337 … … 1441 1339 const QPathEdge *ep = list.edge(status.edge); 1442 1340 1443 if (ep->bezier != bezier || (bezier && t0 != ep->t1 && t1 != ep->t0)) { 1444 if (bezier) { 1445 QBezier sub = bezier->bezierOnInterval(t0, t1); 1446 1447 if (forward) 1448 path.cubicTo(sub.pt2(), sub.pt3(), sub.pt4()); 1449 else 1450 path.cubicTo(sub.pt3(), sub.pt2(), sub.pt1()); 1451 } 1452 1453 bezier = ep->bezier; 1454 t0 = 1; 1455 t1 = 0; 1456 forward = status.direction == QPathEdge::Forward; 1457 } 1458 1459 if (ep->bezier) { 1460 t0 = qMin(t0, ep->t0); 1461 t1 = qMax(t1, ep->t1); 1462 } else 1463 addLineTo(path, *list.vertex(ep->vertex(status.direction))); 1341 addLineTo(path, *list.vertex(ep->vertex(status.direction))); 1464 1342 1465 1343 if (status.traversal == QPathEdge::LeftTraversal) … … 1470 1348 status = list.next(status); 1471 1349 } while (status.edge != edge); 1472 1473 if (bezier) {1474 QBezier sub = bezier->bezierOnInterval(t0, t1);1475 if (forward)1476 path.cubicTo(sub.pt2(), sub.pt3(), sub.pt4());1477 else1478 path.cubicTo(sub.pt3(), sub.pt2(), sub.pt1());1479 }1480 1350 } 1481 1351 … … 1536 1406 return subjectPath.intersects(r2); 1537 1407 1538 QPathSegments a ;1408 QPathSegments a(subjectPath.elementCount()); 1539 1409 a.setPath(subjectPath); 1540 QPathSegments b ;1410 QPathSegments b(clipPath.elementCount()); 1541 1411 b.setPath(clipPath); 1542 1412 … … 1581 1451 return subjectPath.contains(r2); 1582 1452 1583 QPathSegments a ;1453 QPathSegments a(subjectPath.elementCount()); 1584 1454 a.setPath(subjectPath); 1585 QPathSegments b ;1455 QPathSegments b(clipPath.elementCount()); 1586 1456 b.setPath(clipPath); 1587 1457 … … 1705 1575 if (subjectPath == clipPath) 1706 1576 return op == BoolSub ? QPainterPath() : subjectPath; 1577 1578 bool subjectIsRect = pathToRect(subjectPath, 0); 1579 bool clipIsRect = pathToRect(clipPath, 0); 1707 1580 1708 1581 const QRectF clipBounds = clipPath.boundingRect(); … … 1733 1606 1734 1607 if (clipBounds.contains(subjectBounds)) { 1735 QRectF clipRect; 1736 if (pathToRect(clipPath, &clipRect) && clipRect.contains(subjectBounds)) { 1608 if (clipIsRect) { 1737 1609 switch (op) { 1738 1610 case BoolSub: … … 1747 1619 } 1748 1620 } else if (subjectBounds.contains(clipBounds)) { 1749 QRectF subjectRect; 1750 if (pathToRect(subjectPath, &subjectRect) && subjectRect.contains(clipBounds)) { 1621 if (subjectIsRect) { 1751 1622 switch (op) { 1752 1623 case BoolSub: 1753 1624 if (clipPath.fillRule() == Qt::OddEvenFill) { 1754 1625 QPainterPath result = clipPath; 1755 result.addRect(subject Rect);1626 result.addRect(subjectBounds); 1756 1627 return result; 1757 1628 } else { 1758 1629 QPainterPath result = clipPath.simplified(); 1759 result.addRect(subject Rect);1630 result.addRect(subjectBounds); 1760 1631 return result; 1761 1632 } … … 1770 1641 } 1771 1642 } 1643 1644 if (op == BoolAnd) { 1645 if (subjectIsRect) 1646 return intersect(clipPath, subjectBounds); 1647 else if (clipIsRect) 1648 return intersect(subjectPath, clipBounds); 1649 } 1772 1650 } 1773 1651 … … 1931 1809 1932 1810 if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) { 1933 if (ep->bezier) { 1934 qreal maxX = qMax(a.x(), qMax(b.x(), qMax(ep->bezier->x2, ep->bezier->x3))); 1935 qreal minX = qMin(a.x(), qMin(b.x(), qMin(ep->bezier->x2, ep->bezier->x3))); 1936 1937 if (minX > x) { 1938 winding += w; 1939 } else if (maxX > x) { 1940 const qreal t = ep->bezier->tForY(ep->t0, ep->t1, y); 1941 const qreal intersection = ep->bezier->pointAt(t).x(); 1942 1943 if (intersection > x) 1944 winding += w; 1945 } 1946 } else { 1947 qreal intersectionX = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y()); 1948 1949 if (intersectionX > x) 1950 winding += w; 1951 } 1811 qreal intersectionX = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y()); 1812 1813 if (intersectionX > x) 1814 winding += w; 1952 1815 } 1953 1816 } … … 1965 1828 1966 1829 if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) { 1967 if (edge->bezier) { 1968 const qreal t = edge->bezier->tForY(edge->t0, edge->t1, y); 1969 const qreal intersection = edge->bezier->pointAt(t).x(); 1970 1971 const QCrossingEdge edge = { i, intersection }; 1972 crossings << edge; 1973 } else { 1974 const qreal intersection = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y()); 1975 const QCrossingEdge edge = { i, intersection }; 1976 crossings << edge; 1977 } 1830 const qreal intersection = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y()); 1831 const QCrossingEdge edge = { i, intersection }; 1832 crossings << edge; 1978 1833 } 1979 1834 } … … 2053 1908 } 2054 1909 1910 namespace { 1911 1912 QList<QPainterPath> toSubpaths(const QPainterPath &path) 1913 { 1914 1915 QList<QPainterPath> subpaths; 1916 if (path.isEmpty()) 1917 return subpaths; 1918 1919 QPainterPath current; 1920 for (int i = 0; i < path.elementCount(); ++i) { 1921 const QPainterPath::Element &e = path.elementAt(i); 1922 switch (e.type) { 1923 case QPainterPath::MoveToElement: 1924 if (current.elementCount() > 1) 1925 subpaths += current; 1926 current = QPainterPath(); 1927 current.moveTo(e); 1928 break; 1929 case QPainterPath::LineToElement: 1930 current.lineTo(e); 1931 break; 1932 case QPainterPath::CurveToElement: { 1933 current.cubicTo(e, path.elementAt(i + 1), path.elementAt(i + 2)); 1934 i+=2; 1935 break; 1936 } 1937 case QPainterPath::CurveToDataElement: 1938 Q_ASSERT(!"toSubpaths(), bad element type"); 1939 break; 1940 } 1941 } 1942 1943 if (current.elementCount() > 1) 1944 subpaths << current; 1945 1946 return subpaths; 1947 } 1948 1949 enum Edge 1950 { 1951 Left, Top, Right, Bottom 1952 }; 1953 1954 static bool isVertical(Edge edge) 1955 { 1956 return edge == Left || edge == Right; 1957 } 1958 1959 template <Edge edge> 1960 bool compare(const QPointF &p, qreal t) 1961 { 1962 switch (edge) 1963 { 1964 case Left: 1965 return p.x() < t; 1966 case Right: 1967 return p.x() > t; 1968 case Top: 1969 return p.y() < t; 1970 default: 1971 return p.y() > t; 1972 } 1973 } 1974 1975 template <Edge edge> 1976 QPointF intersectLine(const QPointF &a, const QPointF &b, qreal t) 1977 { 1978 QLineF line(a, b); 1979 switch (edge) { 1980 case Left: // fall-through 1981 case Right: 1982 return line.pointAt((t - a.x()) / (b.x() - a.x())); 1983 default: 1984 return line.pointAt((t - a.y()) / (b.y() - a.y())); 1985 } 1986 } 1987 1988 void addLine(QPainterPath &path, const QLineF &line) 1989 { 1990 if (path.elementCount() > 0) 1991 path.lineTo(line.p1()); 1992 else 1993 path.moveTo(line.p1()); 1994 1995 path.lineTo(line.p2()); 1996 } 1997 1998 template <Edge edge> 1999 void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result) 2000 { 2001 bool outA = compare<edge>(a, t); 2002 bool outB = compare<edge>(b, t); 2003 if (outA && outB) 2004 return; 2005 2006 if (outA) 2007 addLine(result, QLineF(intersectLine<edge>(a, b, t), b)); 2008 else if(outB) 2009 addLine(result, QLineF(a, intersectLine<edge>(a, b, t))); 2010 else 2011 addLine(result, QLineF(a, b)); 2012 } 2013 2014 void addBezier(QPainterPath &path, const QBezier &bezier) 2015 { 2016 if (path.elementCount() > 0) 2017 path.lineTo(bezier.pt1()); 2018 else 2019 path.moveTo(bezier.pt1()); 2020 2021 path.cubicTo(bezier.pt2(), bezier.pt3(), bezier.pt4()); 2022 } 2023 2024 template <Edge edge> 2025 void clipBezier(const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, qreal t, QPainterPath &result) 2026 { 2027 QBezier bezier = QBezier::fromPoints(a, b, c, d); 2028 2029 bool outA = compare<edge>(a, t); 2030 bool outB = compare<edge>(b, t); 2031 bool outC = compare<edge>(c, t); 2032 bool outD = compare<edge>(d, t); 2033 2034 int outCount = int(outA) + int(outB) + int(outC) + int(outD); 2035 2036 if (outCount == 4) 2037 return; 2038 2039 if (outCount == 0) { 2040 addBezier(result, bezier); 2041 return; 2042 } 2043 2044 QTransform flip = isVertical(edge) ? QTransform(0, 1, 1, 0, 0, 0) : QTransform(); 2045 QBezier unflipped = bezier; 2046 QBezier flipped = bezier.mapBy(flip); 2047 2048 qreal t0 = 0, t1 = 1; 2049 int stationary = flipped.stationaryYPoints(t0, t1); 2050 2051 qreal segments[4]; 2052 QPointF points[4]; 2053 points[0] = unflipped.pt1(); 2054 segments[0] = 0; 2055 2056 int segmentCount = 0; 2057 if (stationary > 0) { 2058 ++segmentCount; 2059 segments[segmentCount] = t0; 2060 points[segmentCount] = unflipped.pointAt(t0); 2061 } 2062 if (stationary > 1) { 2063 ++segmentCount; 2064 segments[segmentCount] = t1; 2065 points[segmentCount] = unflipped.pointAt(t1); 2066 } 2067 ++segmentCount; 2068 segments[segmentCount] = 1; 2069 points[segmentCount] = unflipped.pt4(); 2070 2071 qreal lastIntersection = 0; 2072 for (int i = 0; i < segmentCount; ++i) { 2073 outA = compare<edge>(points[i], t); 2074 outB = compare<edge>(points[i+1], t); 2075 2076 if (outA != outB) { 2077 qreal intersection = flipped.tForY(segments[i], segments[i+1], t); 2078 2079 if (outB) 2080 addBezier(result, unflipped.getSubRange(lastIntersection, intersection)); 2081 2082 lastIntersection = intersection; 2083 } 2084 } 2085 2086 if (!outB) 2087 addBezier(result, unflipped.getSubRange(lastIntersection, 1)); 2088 } 2089 2090 // clips a single subpath against a single edge 2091 template <Edge edge> 2092 QPainterPath clip(const QPainterPath &path, qreal t) 2093 { 2094 QPainterPath result; 2095 for (int i = 1; i < path.elementCount(); ++i) { 2096 const QPainterPath::Element &element = path.elementAt(i); 2097 Q_ASSERT(!element.isMoveTo()); 2098 if (element.isLineTo()) { 2099 clipLine<edge>(path.elementAt(i-1), path.elementAt(i), t, result); 2100 } else { 2101 clipBezier<edge>(path.elementAt(i-1), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), t, result); 2102 i += 2; 2103 } 2104 } 2105 2106 int last = path.elementCount() - 1; 2107 if (QPointF(path.elementAt(last)) != QPointF(path.elementAt(0))) 2108 clipLine<edge>(path.elementAt(last), path.elementAt(0), t, result); 2109 2110 return result; 2111 } 2112 2113 QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect) 2114 { 2115 QList<QPainterPath> subpaths = toSubpaths(path); 2116 2117 QPainterPath result; 2118 result.setFillRule(path.fillRule()); 2119 for (int i = 0; i < subpaths.size(); ++i) { 2120 QPainterPath subPath = subpaths.at(i); 2121 QRectF bounds = subPath.boundingRect(); 2122 if (bounds.intersects(rect)) { 2123 if (bounds.left() < rect.left()) 2124 subPath = clip<Left>(subPath, rect.left()); 2125 if (bounds.right() > rect.right()) 2126 subPath = clip<Right>(subPath, rect.right()); 2127 2128 bounds = subPath.boundingRect(); 2129 2130 if (bounds.top() < rect.top()) 2131 subPath = clip<Top>(subPath, rect.top()); 2132 if (bounds.bottom() > rect.bottom()) 2133 subPath = clip<Bottom>(subPath, rect.bottom()); 2134 2135 if (subPath.elementCount() > 1) 2136 result.addPath(subPath); 2137 } 2138 } 2139 return result; 2140 } 2141 2142 } 2143 2144 QPainterPath QPathClipper::intersect(const QPainterPath &path, const QRectF &rect) 2145 { 2146 return intersectPath(path, rect); 2147 } 2148 2055 2149 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.