📄 qpainterpath.cpp
字号:
} 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); if (qt_isect_curve_horizontal(first_half, y, x1, x2) || qt_isect_curve_horizontal(second_half, y, x1, 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.bottom() >= y1 && bounds.top() < 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); if (qt_isect_curve_vertical(first_half, x, y1, y2) || qt_isect_curve_vertical(second_half, x, y1, 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 intersects the path; otherwise returns false. There is an intersection if any of the lines making up the rectangle crosses a part of the path or if any part of the rectangle overlaps with any area enclosed by the path. This function respects the current fillRule to determine what is considered inside the path. \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 completely // 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 completely 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 completely 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()) { s << 0; return s; } s << p.elementCount(); for (int i=0; i < p.d_func()->elements.size(); ++i) { const QPainterPath::Element &e = p.d_func()->elements.at(i); s << int(e.type); s << double(e.x) << double(e.y); } s << p.d_func()->cStart; s << int(p.d_func()->fillRule);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -