Qt 4.8
Public Types | Public Functions | Static Public Functions | Private Types | Private Functions | Properties | List of all members
QPathClipper Class Reference

#include <qpathclipper_p.h>

Public Types

enum  Operation { BoolAnd, BoolOr, BoolSub, Simplify }
 

Public Functions

QPainterPath clip (Operation op=BoolAnd)
 
bool contains ()
 
bool intersect ()
 
 QPathClipper (const QPainterPath &subject, const QPainterPath &clip)
 

Static Public Functions

static QPainterPath intersect (const QPainterPath &path, const QRectF &rect)
 
static bool pathToRect (const QPainterPath &path, QRectF *rect=0)
 

Private Types

enum  ClipperMode { ClipMode, CheckMode }
 

Private Functions

bool doClip (QWingedEdge &list, ClipperMode mode)
 
bool handleCrossingEdges (QWingedEdge &list, qreal y, ClipperMode mode)
 

Properties

int aMask
 
int bMask
 
QPainterPath clipPath
 
Operation op
 
QPainterPath subjectPath
 

Detailed Description

Definition at line 71 of file qpathclipper_p.h.

Enumerations

◆ ClipperMode

Enumerator
ClipMode 
CheckMode 

Definition at line 95 of file qpathclipper_p.h.

95  {
96  ClipMode, // do the full clip
97  CheckMode // for contains/intersects (only interested in whether the result path is non-empty)
98  };

◆ Operation

Enumerator
BoolAnd 
BoolOr 
BoolSub 
Simplify 

Definition at line 74 of file qpathclipper_p.h.

Constructors and Destructors

◆ QPathClipper()

QPathClipper::QPathClipper ( const QPainterPath subject,
const QPainterPath clip 
)

Definition at line 1473 of file qpathclipper.cpp.

1475  : subjectPath(subject)
1476  , clipPath(clip)
1477 {
1478  aMask = subjectPath.fillRule() == Qt::WindingFill ? ~0x0 : 0x1;
1479  bMask = clipPath.fillRule() == Qt::WindingFill ? ~0x0 : 0x1;
1480 }
QPainterPath subjectPath
QPainterPath clipPath
Qt::FillRule fillRule() const
Returns the painter path&#39;s currently set fill rule.

Functions

◆ clip()

QPainterPath QPathClipper::clip ( Operation  op = BoolAnd)

Definition at line 1570 of file qpathclipper.cpp.

Referenced by QPainterPath::intersected(), QPainterPath::simplified(), QPainterPath::subtracted(), and QPainterPath::united().

1571 {
1572  op = operation;
1573 
1574  if (op != Simplify) {
1575  if (subjectPath == clipPath)
1576  return op == BoolSub ? QPainterPath() : subjectPath;
1577 
1578  bool subjectIsRect = pathToRect(subjectPath, 0);
1579  bool clipIsRect = pathToRect(clipPath, 0);
1580 
1581  const QRectF clipBounds = clipPath.boundingRect();
1582  const QRectF subjectBounds = subjectPath.boundingRect();
1583 
1584  if (!clipBounds.intersects(subjectBounds)) {
1585  switch (op) {
1586  case BoolSub:
1587  return subjectPath;
1588  case BoolAnd:
1589  return QPainterPath();
1590  case BoolOr: {
1591  QPainterPath result = subjectPath;
1592  if (result.fillRule() == clipPath.fillRule()) {
1593  result.addPath(clipPath);
1594  } else if (result.fillRule() == Qt::WindingFill) {
1595  result = result.simplified();
1596  result.addPath(clipPath);
1597  } else {
1598  result.addPath(clipPath.simplified());
1599  }
1600  return result;
1601  }
1602  default:
1603  break;
1604  }
1605  }
1606 
1607  if (clipBounds.contains(subjectBounds)) {
1608  if (clipIsRect) {
1609  switch (op) {
1610  case BoolSub:
1611  return QPainterPath();
1612  case BoolAnd:
1613  return subjectPath;
1614  case BoolOr:
1615  return clipPath;
1616  default:
1617  break;
1618  }
1619  }
1620  } else if (subjectBounds.contains(clipBounds)) {
1621  if (subjectIsRect) {
1622  switch (op) {
1623  case BoolSub:
1624  if (clipPath.fillRule() == Qt::OddEvenFill) {
1625  QPainterPath result = clipPath;
1626  result.addRect(subjectBounds);
1627  return result;
1628  } else {
1629  QPainterPath result = clipPath.simplified();
1630  result.addRect(subjectBounds);
1631  return result;
1632  }
1633  break;
1634  case BoolAnd:
1635  return clipPath;
1636  case BoolOr:
1637  return subjectPath;
1638  default:
1639  break;
1640  }
1641  }
1642  }
1643 
1644  if (op == BoolAnd) {
1645  if (subjectIsRect)
1646  return intersect(clipPath, subjectBounds);
1647  else if (clipIsRect)
1648  return intersect(subjectPath, clipBounds);
1649  }
1650  }
1651 
1653 
1654  doClip(list, ClipMode);
1655 
1656  QPainterPath path = list.toPath();
1657  return path;
1658 }
void addPath(const QPainterPath &path)
Adds the given path to this path as a closed subpath.
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
bool intersects(const QRectF &r) const
Returns true if this rectangle intersects with the given rectangle (i.
Definition: qrect.cpp:2744
QRectF boundingRect() const
Returns the bounding rectangle of this painter path as a rectangle with floating point precision...
bool contains(const QPointF &p) const
Returns true if the given point is inside or on the edge of the rectangle; otherwise returns false...
Definition: qrect.cpp:2349
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QPainterPath subjectPath
QPainterPath clipPath
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
Qt::FillRule fillRule() const
Returns the painter path&#39;s currently set fill rule.
QPainterPath simplified() const
Returns a simplified version of this path.
static bool pathToRect(const QPainterPath &path, QRectF *rect=0)
Operation op
bool doClip(QWingedEdge &list, ClipperMode mode)

◆ contains()

bool QPathClipper::contains ( )

Definition at line 1436 of file qpathclipper.cpp.

Referenced by QPainterPath::contains().

1437 {
1438  if (subjectPath == clipPath)
1439  return false;
1440 
1443  if (qMax(r1.x(), r2.x()) > qMin(r1.x() + r1.width(), r2.x() + r2.width()) ||
1444  qMax(r1.y(), r2.y()) > qMin(r1.y() + r1.height(), r2.y() + r2.height())) {
1445  // no intersection -> not contained
1446  return false;
1447  }
1448 
1449  bool clipIsRect = pathToRect(clipPath);
1450  if (clipIsRect)
1451  return subjectPath.contains(r2);
1452 
1454  a.setPath(subjectPath);
1456  b.setPath(clipPath);
1457 
1458  QIntersectionFinder finder;
1459  if (finder.hasIntersections(a, b))
1460  return false;
1461 
1462  for (int i = 0; i < clipPath.elementCount(); ++i) {
1464  const QPointF point = clipPath.elementAt(i);
1465  if (!r1.contains(point) || !subjectPath.contains(point))
1466  return false;
1467  }
1468  }
1469 
1470  return true;
1471 }
ElementType type
the type of element
Definition: qpainterpath.h:81
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
long ASN1_INTEGER_get ASN1_INTEGER * a
bool contains(const QPointF &pt) const
Returns true if the given point is inside the path, otherwise returns false.
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
bool contains(const QPointF &p) const
Returns true if the given point is inside or on the edge of the rectangle; otherwise returns false...
Definition: qrect.cpp:2349
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
void setPath(const QPainterPath &path)
QPainterPath subjectPath
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
QPainterPath clipPath
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
bool hasIntersections(const QPathSegments &a, const QPathSegments &b) const
static bool pathToRect(const QPainterPath &path, QRectF *rect=0)
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397

◆ doClip()

bool QPathClipper::doClip ( QWingedEdge list,
ClipperMode  mode 
)
private

Definition at line 1660 of file qpathclipper.cpp.

Referenced by clip().

1661 {
1662  QVector<qreal> y_coords;
1663  y_coords.reserve(list.vertexCount());
1664  for (int i = 0; i < list.vertexCount(); ++i)
1665  y_coords << list.vertex(i)->y;
1666 
1667  qSort(y_coords.begin(), y_coords.end());
1668  y_coords.resize(qRemoveDuplicates(y_coords.begin(), y_coords.end(), fuzzyCompare) - y_coords.begin());
1669 
1670 #ifdef QDEBUG_CLIPPER
1671  printf("sorted y coords:\n");
1672  for (int i = 0; i < y_coords.size(); ++i) {
1673  printf("%.9f\n", y_coords[i]);
1674  }
1675 #endif
1676 
1677  bool found;
1678  do {
1679  found = false;
1680  int index = 0;
1681  qreal maxHeight = 0;
1682  for (int i = 0; i < list.edgeCount(); ++i) {
1683  QPathEdge *edge = list.edge(i);
1684 
1685  // have both sides of this edge already been handled?
1686  if ((edge->flag & 0x3) == 0x3)
1687  continue;
1688 
1689  QPathVertex *a = list.vertex(edge->first);
1690  QPathVertex *b = list.vertex(edge->second);
1691 
1692  if (qFuzzyCompare(a->y, b->y))
1693  continue;
1694 
1695  found = true;
1696 
1697  qreal height = qAbs(a->y - b->y);
1698  if (height > maxHeight) {
1699  index = i;
1700  maxHeight = height;
1701  }
1702  }
1703 
1704  if (found) {
1705  QPathEdge *edge = list.edge(index);
1706 
1707  QPathVertex *a = list.vertex(edge->first);
1708  QPathVertex *b = list.vertex(edge->second);
1709 
1710  // FIXME: this can be optimized by using binary search
1711  const int first = qFuzzyFind(y_coords.begin(), y_coords.end(), qMin(a->y, b->y)) - y_coords.begin();
1712  const int last = qFuzzyFind(y_coords.begin() + first, y_coords.end(), qMax(a->y, b->y)) - y_coords.begin();
1713 
1714  Q_ASSERT(first < y_coords.size() - 1);
1715  Q_ASSERT(last < y_coords.size());
1716 
1717  qreal bestY = 0.5 * (y_coords[first] + y_coords[first+1]);
1718  qreal biggestGap = y_coords[first+1] - y_coords[first];
1719 
1720  for (int i = first + 1; i < last; ++i) {
1721  qreal gap = y_coords[i+1] - y_coords[i];
1722 
1723  if (gap > biggestGap) {
1724  bestY = 0.5 * (y_coords[i] + y_coords[i+1]);
1725  biggestGap = gap;
1726  }
1727  }
1728 
1729 #ifdef QDEBUG_CLIPPER
1730  printf("y: %.9f, gap: %.9f\n", bestY, biggestGap);
1731 #endif
1732 
1733  if (handleCrossingEdges(list, bestY, mode) && mode == CheckMode)
1734  return true;
1735 
1736  edge->flag |= 0x3;
1737  }
1738  } while (found);
1739 
1740  if (mode == ClipMode)
1741  list.simplify();
1742 
1743  return false;
1744 }
static bool fuzzyCompare(qreal a, qreal b)
double qreal
Definition: qglobal.h:1193
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
InputIterator qFuzzyFind(InputIterator first, InputIterator last, qreal val)
QPathVertex * vertex(int vertex)
static Q_DECL_CONSTEXPR bool qFuzzyCompare(double p1, double p2)
Definition: qglobal.h:2030
long ASN1_INTEGER_get ASN1_INTEGER * a
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the vector...
Definition: qvector.h:250
void qSort(RandomAccessIterator start, RandomAccessIterator end)
Definition: qalgorithms.h:177
QPathEdge * edge(int edge)
iterator begin()
Returns an STL-style iterator pointing to the first item in the vector.
Definition: qvector.h:247
quint16 index
void reserve(int size)
Attempts to allocate memory for at least size elements.
Definition: qvector.h:339
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
int edgeCount() const
int vertexCount() const
bool handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode mode)
Iterator qRemoveDuplicates(Iterator begin, Iterator end, Equality eq)

◆ handleCrossingEdges()

bool QPathClipper::handleCrossingEdges ( QWingedEdge list,
qreal  y,
ClipperMode  mode 
)
private

Definition at line 1838 of file qpathclipper.cpp.

Referenced by doClip().

1839 {
1840  QVector<QCrossingEdge> crossings = findCrossings(list, y);
1841 
1842  Q_ASSERT(!crossings.isEmpty());
1843  qSort(crossings.begin(), crossings.end());
1844 
1845  int windingA = 0;
1846  int windingB = 0;
1847 
1848  int windingD = 0;
1849 
1850 #ifdef QDEBUG_CLIPPER
1851  qDebug() << "crossings:" << crossings.size();
1852 #endif
1853  for (int i = 0; i < crossings.size() - 1; ++i) {
1854  int ei = crossings.at(i).edge;
1855  const QPathEdge *edge = list.edge(ei);
1856 
1857  windingA += edge->windingA;
1858  windingB += edge->windingB;
1859 
1860  const bool hasLeft = (edge->flag >> 4) & 1;
1861  const bool hasRight = (edge->flag >> 4) & 2;
1862 
1863  windingD += hasLeft ^ hasRight;
1864 
1865  const bool inA = (windingA & aMask) != 0;
1866  const bool inB = (windingB & bMask) != 0;
1867  const bool inD = (windingD & 0x1) != 0;
1868 
1869  const bool inside = bool_op(inA, inB, op);
1870  const bool add = inD ^ inside;
1871 
1872 #ifdef QDEBUG_CLIPPER
1873  printf("y %f, x %f, inA: %d, inB: %d, inD: %d, inside: %d, flag: %x, bezier: %p, edge: %d\n", y, crossings.at(i).x, inA, inB, inD, inside, edge->flag, edge->bezier, ei);
1874 #endif
1875 
1876  if (add) {
1877  if (mode == CheckMode)
1878  return true;
1879 
1880  qreal y0 = list.vertex(edge->first)->y;
1881  qreal y1 = list.vertex(edge->second)->y;
1882 
1883  if (y0 < y1) {
1884  if (!(edge->flag & 1))
1886 
1887  if (!(edge->flag & 2))
1888  clear(list, ei, QPathEdge::RightTraversal);
1889  } else {
1890  if (!(edge->flag & 1))
1891  clear(list, ei, QPathEdge::LeftTraversal);
1892 
1893  if (!(edge->flag & 2))
1895  }
1896 
1897  ++windingD;
1898  } else {
1899  if (!(edge->flag & 1))
1900  clear(list, ei, QPathEdge::LeftTraversal);
1901 
1902  if (!(edge->flag & 2))
1903  clear(list, ei, QPathEdge::RightTraversal);
1904  }
1905  }
1906 
1907  return false;
1908 }
double qreal
Definition: qglobal.h:1193
static void clear(QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
QPathVertex * vertex(int vertex)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
static void traverse(QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the vector...
Definition: qvector.h:250
Q_CORE_EXPORT void qDebug(const char *,...)
void qSort(RandomAccessIterator start, RandomAccessIterator end)
Definition: qalgorithms.h:177
static QVector< QCrossingEdge > findCrossings(const QWingedEdge &list, qreal y)
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
QPathEdge * edge(int edge)
iterator begin()
Returns an STL-style iterator pointing to the first item in the vector.
Definition: qvector.h:247
bool isEmpty() const
Returns true if the vector has size 0; otherwise returns false.
Definition: qvector.h:139
Operation op
static bool bool_op(bool a, bool b, QPathClipper::Operation op)
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137

◆ intersect() [1/2]

bool QPathClipper::intersect ( )

Definition at line 1385 of file qpathclipper.cpp.

Referenced by clip(), and QPainterPath::intersects().

1386 {
1387  if (subjectPath == clipPath)
1388  return true;
1389 
1392  if (qMax(r1.x(), r2.x()) > qMin(r1.x() + r1.width(), r2.x() + r2.width()) ||
1393  qMax(r1.y(), r2.y()) > qMin(r1.y() + r1.height(), r2.y() + r2.height())) {
1394  // no way we could intersect
1395  return false;
1396  }
1397 
1398  bool subjectIsRect = pathToRect(subjectPath);
1399  bool clipIsRect = pathToRect(clipPath);
1400 
1401  if (subjectIsRect && clipIsRect)
1402  return true;
1403  else if (subjectIsRect)
1404  return clipPath.intersects(r1);
1405  else if (clipIsRect)
1406  return subjectPath.intersects(r2);
1407 
1409  a.setPath(subjectPath);
1411  b.setPath(clipPath);
1412 
1413  QIntersectionFinder finder;
1414  if (finder.hasIntersections(a, b))
1415  return true;
1416 
1417  for (int i = 0; i < clipPath.elementCount(); ++i) {
1419  const QPointF point = clipPath.elementAt(i);
1420  if (r1.contains(point) && subjectPath.contains(point))
1421  return true;
1422  }
1423  }
1424 
1425  for (int i = 0; i < subjectPath.elementCount(); ++i) {
1427  const QPointF point = subjectPath.elementAt(i);
1428  if (r2.contains(point) && clipPath.contains(point))
1429  return true;
1430  }
1431  }
1432 
1433  return false;
1434 }
ElementType type
the type of element
Definition: qpainterpath.h:81
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
long ASN1_INTEGER_get ASN1_INTEGER * a
bool intersects(const QRectF &rect) const
Returns true if any point in the given rectangle intersects the path; otherwise returns false...
bool contains(const QPointF &pt) const
Returns true if the given point is inside the path, otherwise returns false.
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
bool contains(const QPointF &p) const
Returns true if the given point is inside or on the edge of the rectangle; otherwise returns false...
Definition: qrect.cpp:2349
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
void setPath(const QPainterPath &path)
QPainterPath subjectPath
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
QPainterPath clipPath
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
bool hasIntersections(const QPathSegments &a, const QPathSegments &b) const
static bool pathToRect(const QPainterPath &path, QRectF *rect=0)
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397

◆ intersect() [2/2]

QPainterPath QPathClipper::intersect ( const QPainterPath path,
const QRectF rect 
)
static

Definition at line 2144 of file qpathclipper.cpp.

2145 {
2146  return intersectPath(path, rect);
2147 }

◆ pathToRect()

bool QPathClipper::pathToRect ( const QPainterPath path,
QRectF rect = 0 
)
static

Definition at line 1531 of file qpathclipper.cpp.

Referenced by clip(), and setClip().

1532 {
1533  if (path.elementCount() != 5)
1534  return false;
1535 
1536  const bool mightBeRect = path.elementAt(0).isMoveTo()
1537  && path.elementAt(1).isLineTo()
1538  && path.elementAt(2).isLineTo()
1539  && path.elementAt(3).isLineTo()
1540  && path.elementAt(4).isLineTo();
1541 
1542  if (!mightBeRect)
1543  return false;
1544 
1545  const qreal x1 = path.elementAt(0).x;
1546  const qreal y1 = path.elementAt(0).y;
1547 
1548  const qreal x2 = path.elementAt(1).x;
1549  const qreal y2 = path.elementAt(2).y;
1550 
1551  if (path.elementAt(1).y != y1)
1552  return false;
1553 
1554  if (path.elementAt(2).x != x2)
1555  return false;
1556 
1557  if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)
1558  return false;
1559 
1560  if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)
1561  return false;
1562 
1563  if (rect)
1564  rect->setCoords(x1, y1, x2, y2);
1565 
1566  return true;
1567 }
double qreal
Definition: qglobal.h:1193
bool isLineTo() const
Returns true if the element is a line, otherwise returns false.
Definition: qpainterpath.h:84
qreal y
the y coordinate of the element&#39;s position.
Definition: qpainterpath.h:80
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
void setCoords(qreal x1, qreal y1, qreal x2, qreal y2)
Sets the coordinates of the rectangle&#39;s top-left corner to (x1, y1), and the coordinates of its botto...
Definition: qrect.h:770
bool isMoveTo() const
Returns true if the element is moving the current position, otherwise returns false.
Definition: qpainterpath.h:83
qreal x
the x coordinate of the element&#39;s position.
Definition: qpainterpath.h:79
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397

Properties

◆ aMask

int QPathClipper::aMask
private

Definition at line 107 of file qpathclipper_p.h.

Referenced by handleCrossingEdges(), and QPathClipper().

◆ bMask

int QPathClipper::bMask
private

Definition at line 108 of file qpathclipper_p.h.

Referenced by handleCrossingEdges(), and QPathClipper().

◆ clipPath

QPainterPath QPathClipper::clipPath
private

Definition at line 104 of file qpathclipper_p.h.

Referenced by clip(), and QPathClipper().

◆ op

Operation QPathClipper::op
private

Definition at line 105 of file qpathclipper_p.h.

Referenced by clip(), and handleCrossingEdges().

◆ subjectPath

QPainterPath QPathClipper::subjectPath
private

Definition at line 103 of file qpathclipper_p.h.

Referenced by clip(), and QPathClipper().


The documentation for this class was generated from the following files: