📄 qpainterpath.cpp
字号:
if (bounds.width() < lower_bound && bounds.height() < lower_bound) { // We make the assumption here that the curve starts to // approximate a line after while (i.e. that it doesn't // change direction drastically during its slope) if (bezier.pt1().x() <= x) { (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1); } return; } // split curve and try again... QBezier first_half, second_half; bezier.split(&first_half, &second_half); qt_painterpath_isect_curve(first_half, pt, winding); qt_painterpath_isect_curve(second_half, pt, winding); }}/*! \fn bool QPainterPath::contains(const QPointF &point) const Returns true if the given \a point is inside the path, otherwise returns false. \sa intersects()*/bool QPainterPath::contains(const QPointF &pt) const{ if (isEmpty()) return false; QPainterPathData *d = d_func(); int winding_number = 0; QPointF last_pt; QPointF last_start; for (int i=0; i<d->elements.size(); ++i) { const Element &e = d->elements.at(i); switch (e.type) { case MoveToElement: if (i > 0) // implicitly close all paths. qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number); last_start = last_pt = e; break; case LineToElement: qt_painterpath_isect_line(last_pt, e, pt, &winding_number); last_pt = e; break; case CurveToElement: { const QPainterPath::Element &cp2 = d->elements.at(++i); const QPainterPath::Element &ep = d->elements.at(++i); qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep), pt, &winding_number); last_pt = ep; } break; default: break; } } // implicitly close last subpath if (last_pt != last_start) qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number); return (d->fillRule == Qt::WindingFill ? (winding_number != 0) : ((winding_number % 2) != 0));}static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2, const QRectF &rect){ qreal left = rect.left(); qreal right = rect.right(); qreal top = rect.top(); qreal bottom = rect.bottom(); enum { Left, Right, Top, Bottom }; // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html int p1 = ((x1 < left) << Left) | ((x1 > right) << Right) | ((y1 < top) << Top) | ((y1 > bottom) << Bottom); int p2 = ((x2 < left) << Left) | ((x2 > right) << Right) | ((y2 < top) << Top) | ((y2 > bottom) << Bottom); if (p1 & p2) // completely inside return false; if (p1 | p2) { qreal dx = x2 - x1; qreal dy = y2 - y1; // clip x coordinates if (x1 < left) { y1 += dy/dx * (left - x1); x1 = left; } else if (x1 > right) { y1 -= dy/dx * (x1 - right); x1 = right; } if (x2 < left) { y2 += dy/dx * (left - x2); x2 = left; } else if (x2 > right) { y2 -= dy/dx * (x2 - right); x2 = right; } p1 = ((y1 < top) << Top) | ((y1 > bottom) << Bottom); p2 = ((y2 < top) << Top) | ((y2 > bottom) << Bottom); if (p1 & p2) return false; // clip y coordinates if (y1 < top) { x1 += dx/dy * (top - y1); y1 = top; } else if (y1 > bottom) { x1 -= dx/dy * (y1 - bottom); y1 = bottom; } if (y2 < top) { x2 += dx/dy * (top - y2); y2 = top; } else if (y2 > bottom) { x2 -= dx/dy * (y2 - bottom); y2 = bottom; } p1 = ((x1 < left) << Left) | ((x1 > right) << Right); p2 = ((x2 < left) << Left) | ((x2 > right) << Right); if (p1 & p2) return false; return true; } return false;}static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2){ QRectF bounds = bezier.bounds(); if (y >= bounds.top() && y < bounds.bottom() && bounds.right() >= x1 && bounds.left() < x2) { const qreal lower_bound = .01; if (bounds.width() < lower_bound && bounds.height() < lower_bound) return true; QBezier first_half, second_half; bezier.split(&first_half, &second_half); qreal midpoint = x1 + (x2 - x1) / 2; if (qt_isect_curve_horizontal(first_half, y, x1, midpoint) || qt_isect_curve_horizontal(first_half, y, midpoint, x2) || qt_isect_curve_horizontal(second_half, y, x1, midpoint) || qt_isect_curve_horizontal(second_half, y, midpoint, x2)) return true; } return false;}static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2){ QRectF bounds = bezier.bounds(); if (x >= bounds.left() && x < bounds.right() && bounds.top() >= y1 && bounds.bottom() < y2) { const qreal lower_bound = .01; if (bounds.width() < lower_bound && bounds.height() < lower_bound) return true; QBezier first_half, second_half; bezier.split(&first_half, &second_half); qreal midpoint = y1 + (y2 - y1) / 2; if (qt_isect_curve_horizontal(first_half, x, y1, midpoint) || qt_isect_curve_horizontal(first_half, x, midpoint, y2) || qt_isect_curve_horizontal(second_half, x, y1, midpoint) || qt_isect_curve_horizontal(second_half, x, midpoint, y2)) return true; } return false;}/* Returns true if any lines or curves cross the four edges in of rect*/static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect){ QPointF last_pt; QPointF last_start; for (int i=0; i<path->elementCount(); ++i) { const QPainterPath::Element &e = path->elementAt(i); switch (e.type) { case QPainterPath::MoveToElement: if (i > 0 && qFuzzyCompare(last_pt.x(), last_start.y()) && qFuzzyCompare(last_pt.y(), last_start.y()) && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), last_start.x(), last_start.y(), rect)) return true; last_start = last_pt = e; break; case QPainterPath::LineToElement: if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect)) return true; last_pt = e; break; case QPainterPath::CurveToElement: { QPointF cp2 = path->elementAt(++i); QPointF ep = path->elementAt(++i); QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep); if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right()) || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right()) || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom()) || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom())) return true; last_pt = ep; } break; default: break; } } // implicitly close last subpath if (last_pt != last_start && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), last_start.x(), last_start.y(), rect)) return true; return false;}/*! \fn bool QPainterPath::intersects(const QRectF &rectangle) const Returns true if any point in the given \a rectangle is inside the path; otherwise returns false. \sa contains()*/bool QPainterPath::intersects(const QRectF &rect) const{ if (isEmpty() || !controlPointRect().intersects(rect)) return false; // If any path element cross the rect its bound to be an intersection if (qt_painterpath_check_crossing(this, rect)) return true; if (contains(rect.center())) return true; Q_D(QPainterPath); // Check if the rectangle surounds any subpath... for (int i=0; i<d->elements.size(); ++i) { const Element &e = d->elements.at(i); if (e.type == QPainterPath::MoveToElement && rect.contains(e)) return true; } return false;}/*! \fn bool QPainterPath::contains(const QRectF &rectangle) const \overload Returns true if the given \a rectangle is inside the path, otherwise returns false.*/bool QPainterPath::contains(const QRectF &rect) const{ Q_D(QPainterPath); // the path is empty or the control point rect doesn't completly // cover the rectangle we abort stratight away. if (isEmpty() || !controlPointRect().contains(rect)) return false; // if there are intersections, chances are that the rect is not // contained, except if we have winding rule, in which case it // still might. if (qt_painterpath_check_crossing(this, rect)) { if (fillRule() == Qt::OddEvenFill) { return false; } else { // Do some wague sampling in the winding case. This is not // precise but it should mostly be good enough. if (!contains(rect.topLeft()) || !contains(rect.topRight()) || !contains(rect.bottomRight()) || !contains(rect.bottomLeft())) return false; } } // If there exists a point inside that is not part of the path its // because: rectangle lies completly outside path or a subpath // excludes parts of the rectangle. Both cases mean that the rect // is not contained if (!contains(rect.center())) return false; // If there are any subpaths inside this rectangle we need to // check if they are still contained as a result of the fill // rule. This can only be the case for WindingFill though. For // OddEvenFill the rect will never be contained if it surrounds a // subpath. (the case where two subpaths are completly identical // can be argued but we choose to neglect it). for (int i=0; i<d->elements.size(); ++i) { const Element &e = d->elements.at(i); if (e.type == QPainterPath::MoveToElement && rect.contains(e)) { if (fillRule() == Qt::OddEvenFill) return false; bool stop = false; for (; !stop && i<d->elements.size(); ++i) { const Element &el = d->elements.at(i); switch (el.type) { case MoveToElement: stop = true; break; case LineToElement: if (!contains(el)) return false; break; case CurveToElement: if (!contains(d->elements.at(i+2))) return false; i += 2; break; default: break; } } // compensate for the last ++i in the inner for --i; } } return true;}/*! Returns true if this painterpath is equal to the given \a path. Note that comparing paths may involve a per element comparison which can be slow for complex paths. \sa operator!=()*/bool QPainterPath::operator==(const QPainterPath &path) const{ QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func()); if (path.d_func() == d) return true; else if (!d || !path.d_func()) return false; bool equal = d->fillRule == path.d_func()->fillRule && d->elements.size() == path.d_func()->elements.size(); for (int i = 0; i < d->elements.size() && equal; ++i) equal = d->elements.at(i) == path.d_func()->elements.at(i); return equal;}/*! Returns true if this painter path differs from the given \a path. Note that comparing paths may involve a per element comparison which can be slow for complex paths. \sa operator==()*/bool QPainterPath::operator!=(const QPainterPath &path) const{ return !(*this==path);}#ifndef QT_NO_DATASTREAM/*! \fn QDataStream &operator<<(QDataStream &stream, const QPainterPath &path) \relates QPainterPath Writes the given painter \a path to the given \a stream, and returns a reference to the \a stream. \sa {Format of the QDataStream Operators}*/QDataStream &operator<<(QDataStream &s, const QPainterPath &p){ if (p.isEmpty()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -