src/gui/painting/qpainterpath.cpp File Reference

#include "qpainterpath.h"
#include "qpainterpath_p.h"
#include <qbitmap.h>
#include <qdebug.h>
#include <qiodevice.h>
#include <qlist.h>
#include <qmatrix.h>
#include <qpen.h>
#include <qpolygon.h>
#include <qtextlayout.h>
#include <qvarlengtharray.h>
#include <private/qbezier_p.h>
#include <private/qfontengine_p.h>
#include <private/qmath_p.h>
#include <private/qnumeric_p.h>
#include <private/qobject_p.h>
#include <private/qstroker_p.h>
#include <private/qtextengine_p.h>
#include <limits.h>
#include <math.h>

Include dependency graph for qpainterpath.cpp:

Go to the source code of this file.

Classes

class  QPainterPathStrokerPrivate

Defines

#define M_PI   3.14159265358979323846
#define PM_INIT
#define PM_MEASURE(x)
#define PM_DISPLAY
#define KAPPA   0.5522847498
#define ANGLE(t)   ((t) * 2 * M_PI / 360.0)
#define QT_BEZIER_A(bezier, coord)
#define QT_BEZIER_B(bezier, coord)
#define QT_BEZIER_C(bezier, coord)
#define QT_BEZIER_CHECK_T(bezier, t)

Functions

QPainterPath qt_stroke_dash (const QPainterPath &path, qreal *dashes, int dashCount)
void qt_find_ellipse_coords (const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
static QRectF qt_painterpath_bezier_extrema (const QBezier &b)
static bool rect_intersects (const QRectF &r1, const QRectF &r2)
static void qt_painterpath_isect_line (const QPointF &p1, const QPointF &p2, const QPointF &pos, int *winding)
static void qt_painterpath_isect_curve (const QBezier &bezier, const QPointF &pt, int *winding)
static bool qt_painterpath_isect_line_rect (qreal x1, qreal y1, qreal x2, qreal y2, const QRectF &rect)
static bool qt_isect_curve_horizontal (const QBezier &bezier, qreal y, qreal x1, qreal x2)
static bool qt_isect_curve_vertical (const QBezier &bezier, qreal x, qreal y1, qreal y2)
static bool qt_painterpath_check_crossing (const QPainterPath *path, const QRectF &rect)
QDataStreamoperator<< (QDataStream &s, const QPainterPath &p)
QDataStreamoperator>> (QDataStream &s, QPainterPath &p)
void qt_path_stroke_move_to (qfixed x, qfixed y, void *data)
void qt_path_stroke_line_to (qfixed x, qfixed y, void *data)
void qt_path_stroke_cubic_to (qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data)


Define Documentation

#define ANGLE (  )     ((t) * 2 * M_PI / 360.0)

Referenced by qt_curves_for_arc(), and qt_find_ellipse_coords().

#define KAPPA   0.5522847498

Definition at line 72 of file qpainterpath.cpp.

#define M_PI   3.14159265358979323846

Definition at line 58 of file qpainterpath.cpp.

Referenced by PieView::indexAt(), qdesigner_internal::QtGradientWidget::mouseMoveEvent(), qdesigner_internal::QtGradientWidget::mousePressEvent(), qdesigner_internal::QtGradientWidget::paintEvent(), pathArc(), pathArcSegment(), and KAsteroidsView::processShip().

#define PM_DISPLAY

Definition at line 66 of file qpainterpath.cpp.

#define PM_INIT

Definition at line 64 of file qpainterpath.cpp.

#define PM_MEASURE (  ) 

Definition at line 65 of file qpainterpath.cpp.

#define QT_BEZIER_A ( bezier,
coord   ) 

Value:

3 * (-bezier.coord##1 \
                                        + 3*bezier.coord##2 \
                                        - 3*bezier.coord##3 \
                                        +bezier.coord##4)

Definition at line 1287 of file qpainterpath.cpp.

Referenced by qt_painterpath_bezier_extrema().

#define QT_BEZIER_B ( bezier,
coord   ) 

Value:

6 * (bezier.coord##1 \
                                        - 2*bezier.coord##2 \
                                        + bezier.coord##3)

Definition at line 1292 of file qpainterpath.cpp.

Referenced by qt_painterpath_bezier_extrema().

#define QT_BEZIER_C ( bezier,
coord   ) 

Value:

3 * (- bezier.coord##1 \
                                        + bezier.coord##2)

Definition at line 1296 of file qpainterpath.cpp.

Referenced by qt_painterpath_bezier_extrema().

#define QT_BEZIER_CHECK_T ( bezier,
 ) 

Value:

if (t >= 0 && t <= 1) { \
        QPointF p(b.pointAt(t)); \
        if (p.x() < minx) minx = p.x(); \
        else if (p.x() > maxx) maxx = p.x(); \
        if (p.y() < miny) miny = p.y(); \
        else if (p.y() > maxy) maxy = p.y(); \
    }

Definition at line 1299 of file qpainterpath.cpp.

Referenced by qt_painterpath_bezier_extrema().


Function Documentation

QDataStream& operator<< ( QDataStream s,
const QPainterPath p 
)

Definition at line 2199 of file qpainterpath.cpp.

02200 {
02201     if (p.isEmpty()) {
02202         s << 0;
02203         return s;
02204     }
02205 
02206     s << p.elementCount();
02207     for (int i=0; i < p.d_func()->elements.size(); ++i) {
02208         const QPainterPath::Element &e = p.d_func()->elements.at(i);
02209         s << int(e.type);
02210         s << double(e.x) << double(e.y);
02211     }
02212     s << p.d_func()->cStart;
02213     s << int(p.d_func()->fillRule);
02214     return s;
02215 }

QDataStream& operator>> ( QDataStream s,
QPainterPath p 
)

Definition at line 2226 of file qpainterpath.cpp.

02227 {
02228     int size;
02229     s >> size;
02230 
02231     if (size == 0)
02232         return s;
02233 
02234     p.ensureData(); // in case if p.d_func() == 0
02235     if (p.d_func()->elements.size() == 1) {
02236         Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
02237         p.d_func()->elements.clear();
02238     }
02239     p.d_func()->elements.reserve(p.d_func()->elements.size() + size);
02240     for (int i=0; i<size; ++i) {
02241         int type;
02242         double x, y;
02243         s >> type;
02244         s >> x;
02245         s >> y;
02246         Q_ASSERT(type >= 0 && type <= 3);
02247 #ifndef QT_NO_DEBUG
02248         if (qIsNan(x) || qIsNan(y))
02249             qWarning("QDataStream::operator>>: Adding a NaN element to path, results are undefined");
02250 #endif
02251         QPainterPath::Element elm = { x, y, QPainterPath::ElementType(type) };
02252         p.d_func()->elements.append(elm);
02253     }
02254     s >> p.d_func()->cStart;
02255     int fillRule;
02256     s >> fillRule;
02257     Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill);
02258     p.d_func()->fillRule = Qt::FillRule(fillRule);
02259     return s;
02260 }

void qt_find_ellipse_coords ( const QRectF r,
qreal  angle,
qreal  length,
QPointF startPoint,
QPointF endPoint 
)

Definition at line 80 of file qpainterpath.cpp.

References a, ANGLE, b, QRectF::center(), QRectF::height(), and QRectF::width().

Referenced by QPainterPath::arcMoveTo(), and Q3PointArray::makeArc().

00082 {
00083 #define ANGLE(t) ((t) * 2 * M_PI / 360.0)
00084     qreal a = r.width() / 2.0;
00085     qreal b = r.height() / 2.0;
00086 
00087     if (startPoint) {
00088         *startPoint = r.center()
00089                       + QPointF(a * cos(ANGLE(angle)), -b * sin(ANGLE(angle)));
00090     }
00091     if (endPoint) {
00092         *endPoint = r.center()
00093                     + QPointF(a * cos(ANGLE(angle + length)), -b * sin(ANGLE(angle + length)));
00094     }
00095 }

Here is the call graph for this function:

static bool qt_isect_curve_horizontal ( const QBezier bezier,
qreal  y,
qreal  x1,
qreal  x2 
) [static]

Definition at line 1931 of file qpainterpath.cpp.

References QRectF::bottom(), QBezier::bounds(), QRectF::height(), QRectF::left(), QRectF::right(), QBezier::split(), QRectF::top(), and QRectF::width().

Referenced by qt_isect_curve_vertical(), and qt_painterpath_check_crossing().

01932 {
01933     QRectF bounds = bezier.bounds();
01934 
01935     if (y >= bounds.top() && y < bounds.bottom()
01936         && bounds.right() >= x1 && bounds.left() < x2) {
01937         const qreal lower_bound = .01;
01938         if (bounds.width() < lower_bound && bounds.height() < lower_bound)
01939             return true;
01940 
01941         QBezier first_half, second_half;
01942         bezier.split(&first_half, &second_half);
01943         qreal midpoint = x1 + (x2 - x1) / 2;
01944         if (qt_isect_curve_horizontal(first_half, y, x1, midpoint)
01945             || qt_isect_curve_horizontal(first_half, y, midpoint, x2)
01946             || qt_isect_curve_horizontal(second_half, y, x1, midpoint)
01947             || qt_isect_curve_horizontal(second_half, y, midpoint, x2))
01948             return true;
01949     }
01950     return false;
01951 }

Here is the call graph for this function:

static bool qt_isect_curve_vertical ( const QBezier bezier,
qreal  x,
qreal  y1,
qreal  y2 
) [static]

Definition at line 1953 of file qpainterpath.cpp.

References QRectF::bottom(), QBezier::bounds(), QRectF::height(), QRectF::left(), qt_isect_curve_horizontal(), QRectF::right(), QBezier::split(), QRectF::top(), and QRectF::width().

Referenced by qt_painterpath_check_crossing().

01954 {
01955     QRectF bounds = bezier.bounds();
01956 
01957     if (x >= bounds.left() && x < bounds.right()
01958         && bounds.top() >= y1 && bounds.bottom() < y2) {
01959         const qreal lower_bound = .01;
01960         if (bounds.width() < lower_bound && bounds.height() < lower_bound)
01961             return true;
01962 
01963         QBezier first_half, second_half;
01964         bezier.split(&first_half, &second_half);
01965         qreal midpoint = y1 + (y2 - y1) / 2;
01966         if (qt_isect_curve_horizontal(first_half, x, y1, midpoint)
01967             || qt_isect_curve_horizontal(first_half, x, midpoint, y2)
01968             || qt_isect_curve_horizontal(second_half, x, y1, midpoint)
01969             || qt_isect_curve_horizontal(second_half, x, midpoint, y2))
01970             return true;
01971     }
01972     return false;
01973 }

Here is the call graph for this function:

static QRectF qt_painterpath_bezier_extrema ( const QBezier b  )  [static]

Definition at line 1309 of file qpainterpath.cpp.

References b, QT_BEZIER_A, QT_BEZIER_B, QT_BEZIER_C, QT_BEZIER_CHECK_T, t, x, and y.

Referenced by QPainterPath::boundingRect().

01310 {
01311     qreal minx, miny, maxx, maxy;
01312 
01313     // initialize with end points
01314     if (b.x1 < b.x4) {
01315         minx = b.x1;
01316         maxx = b.x4;
01317     } else {
01318         minx = b.x4;
01319         maxx = b.x1;
01320     }
01321     if (b.y1 < b.y4) {
01322         miny = b.y1;
01323         maxy = b.y4;
01324     } else {
01325         miny = b.y4;
01326         maxy = b.y1;
01327     }
01328 
01329     // Update for the X extrema
01330     {
01331         qreal ax = QT_BEZIER_A(b, x);
01332         qreal bx = QT_BEZIER_B(b, x);
01333         qreal cx = QT_BEZIER_C(b, x);
01334         // specialcase quadratic curves to avoid div by zero
01335         if (qFuzzyCompare(ax, 0)) {
01336 
01337             // linear curves are covered by initialization.
01338             if (!qFuzzyCompare(bx, 0)) {
01339                 qreal t = -cx / bx;
01340                 QT_BEZIER_CHECK_T(b, t);
01341             }
01342 
01343         } else {
01344             qreal t1 = (-bx + sqrt(bx * bx - 4 * ax * cx)) / (2 * ax);
01345             QT_BEZIER_CHECK_T(b, t1);
01346 
01347             qreal t2 = (-bx - sqrt(bx * bx - 4 * ax * cx)) / (2 * ax);
01348             QT_BEZIER_CHECK_T(b, t2);
01349         }
01350     }
01351 
01352     // Update for the Y extrema
01353     {
01354         qreal ay = QT_BEZIER_A(b, y);
01355         qreal by = QT_BEZIER_B(b, y);
01356         qreal cy = QT_BEZIER_C(b, y);
01357 
01358         // specialcase quadratic curves to avoid div by zero
01359         if (qFuzzyCompare(ay, 0)) {
01360 
01361             // linear curves are covered by initialization.
01362             if (!qFuzzyCompare(by, 0)) {
01363                 qreal t = -cy / by;
01364                 QT_BEZIER_CHECK_T(b, t);
01365             }
01366 
01367         } else {
01368             qreal t1 = (-by + sqrt(by * by - 4 * ay * cy)) / (2 * ay);
01369             QT_BEZIER_CHECK_T(b, t1);
01370 
01371             qreal t2 = (-by - sqrt(by * by - 4 * ay * cy)) / (2 * ay);
01372             QT_BEZIER_CHECK_T(b, t2);
01373         }
01374     }
01375     return QRectF(minx, miny, maxx - minx, maxy - miny);
01376 }

static bool qt_painterpath_check_crossing ( const QPainterPath path,
const QRectF rect 
) [static]

Definition at line 1978 of file qpainterpath.cpp.

References QRectF::bottom(), QPainterPath::CurveToElement, QBezier::fromPoints(), i, QRectF::left(), QPainterPath::LineToElement, QPainterPath::MoveToElement, path, qt_isect_curve_horizontal(), qt_isect_curve_vertical(), qt_painterpath_isect_line_rect(), QRectF::right(), QRectF::top(), QPointF::x(), and QPointF::y().

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

01979 {
01980     QPointF last_pt;
01981     QPointF last_start;
01982     for (int i=0; i<path->elementCount(); ++i) {
01983         const QPainterPath::Element &e = path->elementAt(i);
01984 
01985         switch (e.type) {
01986 
01987         case QPainterPath::MoveToElement:
01988             if (i > 0
01989                 && qFuzzyCompare(last_pt.x(), last_start.y())
01990                 && qFuzzyCompare(last_pt.y(), last_start.y())
01991                 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
01992                                                   last_start.x(), last_start.y(), rect))
01993                 return true;
01994             last_start = last_pt = e;
01995             break;
01996 
01997         case QPainterPath::LineToElement:
01998             if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
01999                 return true;
02000             last_pt = e;
02001             break;
02002 
02003         case QPainterPath::CurveToElement:
02004             {
02005                 QPointF cp2 = path->elementAt(++i);
02006                 QPointF ep = path->elementAt(++i);
02007                 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
02008                 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
02009                     || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
02010                     || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
02011                     || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
02012                     return true;
02013                 last_pt = ep;
02014             }
02015             break;
02016 
02017         default:
02018             break;
02019         }
02020     }
02021 
02022     // implicitly close last subpath
02023     if (last_pt != last_start
02024         && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
02025                                           last_start.x(), last_start.y(), rect))
02026         return true;
02027 
02028     return false;
02029 }

Here is the call graph for this function:

static void qt_painterpath_isect_curve ( const QBezier bezier,
const QPointF pt,
int *  winding 
) [static]

Definition at line 1757 of file qpainterpath.cpp.

References QBezier::bounds(), QRectF::height(), QBezier::pt1(), QBezier::pt4(), QBezier::split(), QRectF::width(), QPointF::x(), x, QRectF::y(), QPointF::y(), and y.

Referenced by QPainterPath::contains().

01759 {
01760     qreal y = pt.y();
01761     qreal x = pt.x();
01762     QRectF bounds = bezier.bounds();
01763 
01764     // potential intersection, divide and try again...
01765     // Please note that a sideeffect of the bottom exclusion is that
01766     // horizontal lines are dropped, but this is correct according to
01767     // scan conversion rules.
01768     if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
01769 
01770         // hit lower limit... This is a rough threshold, but its a
01771         // tradeoff between speed and precision.
01772         const qreal lower_bound = .01;
01773         if (bounds.width() < lower_bound && bounds.height() < lower_bound) {
01774             // We make the assumption here that the curve starts to
01775             // approximate a line after while (i.e. that it doesn't
01776             // change direction drastically during its slope)
01777             if (bezier.pt1().x() <= x) {
01778                 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
01779             }
01780             return;
01781         }
01782 
01783         // split curve and try again...
01784         QBezier first_half, second_half;
01785         bezier.split(&first_half, &second_half);
01786         qt_painterpath_isect_curve(first_half, pt, winding);
01787         qt_painterpath_isect_curve(second_half, pt, winding);
01788     }
01789 }

Here is the call graph for this function:

static void qt_painterpath_isect_line ( const QPointF p1,
const QPointF p2,
const QPointF pos,
int *  winding 
) [static]

Definition at line 1727 of file qpainterpath.cpp.

References QPointF::x(), x, QPointF::y(), and y.

Referenced by QPainterPath::contains().

01729 {
01730     qreal x1 = p1.x();
01731     qreal y1 = p1.y();
01732     qreal x2 = p2.x();
01733     qreal y2 = p2.y();
01734     qreal y = pos.y();
01735 
01736     int dir = 1;
01737 
01738     if (qFuzzyCompare(y1, y2)) {
01739         // ignore horizontal lines according to scan conversion rule
01740         return;
01741     } else if (y2 < y1) {
01742         qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
01743         qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
01744         dir = -1;
01745     }
01746 
01747     if (y >= y1 && y < y2) {
01748         qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
01749 
01750         // count up the winding number if we're
01751         if (x<=pos.x()) {
01752             (*winding) += dir;
01753         }
01754     }
01755 }

Here is the call graph for this function:

static bool qt_painterpath_isect_line_rect ( qreal  x1,
qreal  y1,
qreal  x2,
qreal  y2,
const QRectF rect 
) [static]

Definition at line 1851 of file qpainterpath.cpp.

References QCss::Bottom, QRectF::bottom(), QTextStream::left(), QCss::Left, QRectF::left(), QCss::Right, QTextStream::right(), QRectF::right(), QCss::Top, and QRectF::top().

Referenced by qt_painterpath_check_crossing().

01853 {
01854     qreal left = rect.left();
01855     qreal right = rect.right();
01856     qreal top = rect.top();
01857     qreal bottom = rect.bottom();
01858 
01859     enum { Left, Right, Top, Bottom };
01860     // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
01861     int p1 = ((x1 < left) << Left)
01862              | ((x1 > right) << Right)
01863              | ((y1 < top) << Top)
01864              | ((y1 > bottom) << Bottom);
01865     int p2 = ((x2 < left) << Left)
01866              | ((x2 > right) << Right)
01867              | ((y2 < top) << Top)
01868              | ((y2 > bottom) << Bottom);
01869 
01870     if (p1 & p2)
01871         // completely inside
01872         return false;
01873 
01874     if (p1 | p2) {
01875         qreal dx = x2 - x1;
01876         qreal dy = y2 - y1;
01877 
01878         // clip x coordinates
01879         if (x1 < left) {
01880             y1 += dy/dx * (left - x1);
01881             x1 = left;
01882         } else if (x1 > right) {
01883             y1 -= dy/dx * (x1 - right);
01884             x1 = right;
01885         }
01886         if (x2 < left) {
01887             y2 += dy/dx * (left - x2);
01888             x2 = left;
01889         } else if (x2 > right) {
01890             y2 -= dy/dx * (x2 - right);
01891             x2 = right;
01892         }
01893 
01894         p1 = ((y1 < top) << Top)
01895              | ((y1 > bottom) << Bottom);
01896         p2 = ((y2 < top) << Top)
01897              | ((y2 > bottom) << Bottom);
01898 
01899         if (p1 & p2)
01900             return false;
01901 
01902         // clip y coordinates
01903         if (y1 < top) {
01904             x1 += dx/dy * (top - y1);
01905             y1 = top;
01906         } else if (y1 > bottom) {
01907             x1 -= dx/dy * (y1 - bottom);
01908             y1 = bottom;
01909         }
01910         if (y2 < top) {
01911             x2 += dx/dy * (top - y2);
01912             y2 = top;
01913         } else if (y2 > bottom) {
01914             x2 -= dx/dy * (y2 - bottom);
01915             y2 = bottom;
01916         }
01917 
01918         p1 = ((x1 < left) << Left)
01919              | ((x1 > right) << Right);
01920         p2 = ((x2 < left) << Left)
01921              | ((x2 > right) << Right);
01922 
01923         if (p1 & p2)
01924             return false;
01925 
01926         return true;
01927     }
01928     return false;
01929 }

Here is the call graph for this function:

void qt_path_stroke_cubic_to ( qfixed  c1x,
qfixed  c1y,
qfixed  c2x,
qfixed  c2y,
qfixed  ex,
qfixed  ey,
void *  data 
)

Definition at line 2278 of file qpainterpath.cpp.

References qt_fixed_to_real.

Referenced by QPainterPathStrokerPrivate::QPainterPathStrokerPrivate().

02282 {
02283     ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
02284                                      qt_fixed_to_real(c2x), qt_fixed_to_real(c2y),
02285                                      qt_fixed_to_real(ex), qt_fixed_to_real(ey));
02286 }

void qt_path_stroke_line_to ( qfixed  x,
qfixed  y,
void *  data 
)

Definition at line 2273 of file qpainterpath.cpp.

References qt_fixed_to_real.

Referenced by QPainterPathStrokerPrivate::QPainterPathStrokerPrivate().

02274 {
02275     ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
02276 }

void qt_path_stroke_move_to ( qfixed  x,
qfixed  y,
void *  data 
)

Definition at line 2268 of file qpainterpath.cpp.

References qt_fixed_to_real.

Referenced by QPainterPathStrokerPrivate::QPainterPathStrokerPrivate().

02269 {
02270     ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
02271 }

QPainterPath qt_stroke_dash ( const QPainterPath path,
qreal *  dashes,
int  dashCount 
)

static bool rect_intersects ( const QRectF r1,
const QRectF r2 
) [inline, static]

Definition at line 1606 of file qpainterpath.cpp.

References QRectF::bottom(), QRectF::left(), qMax(), qMin(), QRectF::right(), and QRectF::top().

Referenced by QRegion::intersects(), and QPainterPath::toFillPolygons().

01607 {
01608     return qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right())
01609         && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom());
01610 }

Here is the call graph for this function:


Generated on Thu Mar 15 13:35:33 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1