src/gui/painting/qstroker.cpp File Reference

#include "private/qstroker_p.h"
#include "private/qbezier_p.h"
#include "private/qmath_p.h"
#include "qline.h"

Include dependency graph for qstroker.cpp:

Go to the source code of this file.

Classes

class  QSubpathForwardIterator
class  QSubpathBackwardIterator
class  QSubpathFlatIterator

Defines

#define ANGLE(t)   ((t) * 2 * Q_PI / 360.0)
#define SIGN(t)   (t > 0 ? 1 : -1)

Functions

template<class Iterator>
bool qt_stroke_side (Iterator *it, QStroker *stroker, bool capFirst, QLineF *startTangent)
static qreal adapted_angle_on_x (const QLineF &line)
QPointF qt_curves_for_arc (const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)


Define Documentation

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

#define SIGN (  )     (t > 0 ? 1 : -1)

Referenced by qt_curves_for_arc().


Function Documentation

static qreal adapted_angle_on_x ( const QLineF line  )  [inline, static]

Definition at line 159 of file qstroker.cpp.

References angle(), QLineF::angle(), and QLineF::dy().

Referenced by QStroker::joinPoints().

00160 {
00161     qreal angle = line.angle(QLineF(0, 0, 1, 0));
00162     if (line.dy() > 0)
00163         angle = 360 - angle;
00164     return angle;
00165 }

Here is the call graph for this function:

QPointF qt_curves_for_arc ( const QRectF rect,
qreal  startAngle,
qreal  sweepLength,
QPointF curves,
int *  point_count 
)

Definition at line 722 of file qstroker.cpp.

References a, ANGLE, b, ceil, QRectF::center(), h, QRectF::height(), i, int, QRectF::isNull(), QLineF::length(), QLineF::p2(), qCos, qIsNan(), qSin, QT_PATH_KAPPA, qWarning(), QLineF::setLength(), SIGN, w, QRectF::width(), QRectF::x(), x, QRectF::y(), and y.

Referenced by QPainterPath::addEllipse(), QPainterPath::arcTo(), QRasterPaintEngine::drawEllipse(), QStroker::joinPoints(), and QStrokerOps::strokeEllipse().

00724 {
00725     Q_ASSERT(point_count);
00726     Q_ASSERT(curves);
00727 
00728 #ifndef QT_NO_DEBUG
00729     if (qIsNan(rect.x()) || qIsNan(rect.y()) || qIsNan(rect.width()) || qIsNan(rect.height())
00730         || qIsNan(startAngle) || qIsNan(sweepLength))
00731         qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");
00732 #endif
00733     *point_count = 0;
00734 
00735     if (rect.isNull()) {
00736         return QPointF();
00737     }
00738 
00739     if (sweepLength > 360) sweepLength = 360;
00740     else if (sweepLength < -360) sweepLength = -360;
00741 
00742     // Special case fast path
00743     if (startAngle == 0.0 && sweepLength == 360.0) {
00744         qreal x = rect.x();
00745         qreal y = rect.y();
00746 
00747         qreal w = rect.width();
00748         qreal w2 = rect.width() / 2;
00749         qreal w2k = w2 * QT_PATH_KAPPA;
00750 
00751         qreal h = rect.height();
00752         qreal h2 = rect.height() / 2;
00753         qreal h2k = h2 * QT_PATH_KAPPA;
00754 
00755         // 0 -> 270 degrees
00756         curves[(*point_count)++] = QPointF(x + w, y + h2 + h2k);
00757         curves[(*point_count)++] = QPointF(x + w2 + w2k, y + h);
00758         curves[(*point_count)++] = QPointF(x + w2, y + h);
00759 
00760         // 270 -> 180 degrees
00761         curves[(*point_count)++] = QPointF(x + w2 - w2k, y + h);
00762         curves[(*point_count)++] = QPointF(x, y + h2 + h2k);
00763         curves[(*point_count)++] = QPointF(x, y + h2);
00764 
00765         // 180 -> 90 degrees
00766         curves[(*point_count)++] = QPointF(x, y + h2 - h2k);
00767         curves[(*point_count)++] = QPointF(x + w2 - w2k, y);
00768         curves[(*point_count)++] = QPointF(x + w2, y);
00769 
00770         // 90 -> 0 degrees
00771         curves[(*point_count)++] = QPointF(x + w2 + w2k, y);
00772         curves[(*point_count)++] = QPointF(x + w, y + h2 - h2k);
00773         curves[(*point_count)++] = QPointF(x + w, y + h2);
00774 
00775         return QPointF(x + w, y + h2);
00776     }
00777 
00778 #define ANGLE(t) ((t) * 2 * Q_PI / 360.0)
00779 #define SIGN(t) (t > 0 ? 1 : -1)
00780     qreal a = rect.width() / 2.0;
00781     qreal b = rect.height() / 2.0;
00782 
00783     qreal absSweepLength = (sweepLength < 0 ? -sweepLength : sweepLength);
00784     int iterations = (int)ceil((absSweepLength) / 90.0);
00785 
00786     QPointF first_point;
00787 
00788     if (iterations == 0) {
00789         first_point = rect.center() + QPointF(a * qCos(ANGLE(startAngle)),
00790                                               -b * qSin(ANGLE(startAngle)));
00791     } else {
00792         qreal clength = sweepLength / iterations;
00793         qreal cosangle1, sinangle1, cosangle2, sinangle2;
00794 
00795         for (int i=0; i<iterations; ++i) {
00796             qreal cangle = startAngle + i * clength;
00797 
00798             cosangle1 = qCos(ANGLE(cangle));
00799             sinangle1 = qSin(ANGLE(cangle));
00800             cosangle2 = qCos(ANGLE(cangle + clength));
00801             sinangle2 = qSin(ANGLE(cangle + clength));
00802 
00803             // Find the start and end point of the curve.
00804             QPointF startPoint = rect.center() + QPointF(a * cosangle1, -b * sinangle1);
00805             QPointF endPoint = rect.center() + QPointF(a * cosangle2, -b * sinangle2);
00806 
00807             // The derived at the start and end point.
00808             qreal sdx = -a * sinangle1;
00809             qreal sdy = -b * cosangle1;
00810             qreal edx = -a * sinangle2;
00811             qreal edy = -b * cosangle2;
00812 
00813             // Creating the tangent lines. We need to reverse their direction if the
00814             // sweep is negative (clockwise)
00815             QLineF controlLine1(startPoint, startPoint + SIGN(sweepLength) * QPointF(sdx, sdy));
00816             QLineF controlLine2(endPoint, endPoint - SIGN(sweepLength) * QPointF(edx, edy));
00817 
00818             // We need to scale down the control lines to match that of the current sweeplength.
00819             // qAbs because we only want to scale, not change direction.
00820             qreal kappa = QT_PATH_KAPPA * qAbs(clength) / 90.0;
00821             // Adjust their length to fit the magic KAPPA length.
00822             controlLine1.setLength(controlLine1.length() * kappa);
00823             controlLine2.setLength(controlLine2.length() * kappa);
00824 
00825             curves[(*point_count)++] = controlLine1.p2();
00826             curves[(*point_count)++] = controlLine2.p2();
00827             curves[(*point_count)++] = endPoint;
00828 
00829             if (i == 0)
00830                 first_point = startPoint;
00831         }
00832     }
00833 
00834     return first_point;
00835 }

Here is the call graph for this function:

template<class Iterator>
bool qt_stroke_side ( Iterator *  it,
QStroker stroker,
bool  capFirst,
QLineF startTangent 
)

Definition at line 579 of file qstroker.cpp.

References QStroker::capStyleMode(), QStroker::curveThreshold(), QLineF::dx(), QLineF::dy(), QStroker::emitCubicTo(), QStroker::emitLineTo(), QStroker::emitMoveTo(), QBezier::fromPoints(), i, QStroker::joinPoints(), QStroker::joinStyleMode(), QLineF::normalVector(), QBezier::pt1(), QBezier::pt3(), QBezier::pt4(), qDebug(), qt_fixed_to_real, qt_real_to_fixed, QLineF::setLength(), QBezier::shifted(), start, QStroker::strokeWidth(), QLineF::translate(), qfixed2d::x, QStrokerOps::Element::x, QPointF::x(), QLineF::x1(), QLineF::x2(), qfixed2d::y, QStrokerOps::Element::y, QPointF::y(), QLineF::y1(), and QLineF::y2().

Referenced by QStroker::processCurrentSubpath().

00583 {
00584     // Used in CurveToElement section below.
00585     const int MAX_OFFSET = 16;
00586     QBezier offsetCurves[MAX_OFFSET];
00587 
00588     Q_ASSERT(it->hasNext()); // The initaial move to
00589     QStrokerOps::Element first_element = it->next();
00590     Q_ASSERT(first_element.isMoveTo());
00591 
00592     qfixed2d start = first_element;
00593 
00594 #ifdef QPP_STROKE_DEBUG
00595     qDebug(" -> (side) [%.2f, %.2f], startPos=%d",
00596            qt_fixed_to_real(start.x),
00597            qt_fixed_to_real(start.y));
00598 #endif
00599 
00600     qfixed2d prev = start;
00601 
00602     bool first = true;
00603 
00604     qfixed offset = stroker->strokeWidth() / 2;
00605 
00606     while (it->hasNext()) {
00607         QStrokerOps::Element e = it->next();
00608 
00609         // LineToElement
00610         if (e.isLineTo()) {
00611 #ifdef QPP_STROKE_DEBUG
00612             qDebug("\n ---> (side) lineto [%.2f, %.2f]", e.x, e.y);
00613 #endif
00614             QLineF line(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y),
00615                         qt_fixed_to_real(e.x), qt_fixed_to_real(e.y));
00616             QLineF normal = line.normalVector();
00617             normal.setLength(offset);
00618             line.translate(normal.dx(), normal.dy());
00619 
00620             // If we are starting a new subpath, move to correct starting point.
00621             if (first) {
00622                 if (capFirst)
00623                     stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode());
00624                 else
00625                     stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1()));
00626                 *startTangent = line;
00627                 first = false;
00628             } else {
00629                 stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode());
00630             }
00631 
00632             // Add the stroke for this line.
00633             stroker->emitLineTo(qt_real_to_fixed(line.x2()),
00634                                 qt_real_to_fixed(line.y2()));
00635             prev = e;
00636 
00637         // CurveToElement
00638         } else if (e.isCurveTo()) {
00639             QStrokerOps::Element cp2 = it->next(); // control point 2
00640             QStrokerOps::Element ep = it->next();  // end point
00641 
00642 #ifdef QPP_STROKE_DEBUG
00643             qDebug("\n ---> (side) cubicTo [%.2f, %.2f]",
00644                    qt_fixed_to_real(ep.x),
00645                    qt_fixed_to_real(ep.y));
00646 #endif
00647 
00648             QBezier bezier =
00649                 QBezier::fromPoints(QPointF(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y)),
00650                                     QPointF(qt_fixed_to_real(e.x), qt_fixed_to_real(e.y)),
00651                                     QPointF(qt_fixed_to_real(cp2.x), qt_fixed_to_real(cp2.y)),
00652                                     QPointF(qt_fixed_to_real(ep.x), qt_fixed_to_real(ep.y)));
00653 
00654             int count = bezier.shifted(offsetCurves,
00655                                        MAX_OFFSET,
00656                                        offset,
00657                                        stroker->curveThreshold());
00658 
00659             if (count) {
00660                 // If we are starting a new subpath, move to correct starting point
00661                 if (first) {
00662                     QPointF pt = offsetCurves[0].pt1();
00663                     if (capFirst) {
00664                         stroker->joinPoints(prev.x, prev.y,
00665                                             QLineF(pt, offsetCurves[0].pt2()),
00666                                             stroker->capStyleMode());
00667                     } else {
00668                         stroker->emitMoveTo(qt_real_to_fixed(pt.x()),
00669                                             qt_real_to_fixed(pt.y()));
00670                     }
00671                     *startTangent = QLineF(offsetCurves[0].pt1(), offsetCurves[0].pt2());
00672                     first = false;
00673                 } else {
00674                     stroker->joinPoints(prev.x, prev.y,
00675                                         QLineF(offsetCurves[0].pt1(), offsetCurves[0].pt2()),
00676                                         stroker->joinStyleMode());
00677                 }
00678 
00679                 // Add these beziers
00680                 for (int i=0; i<count; ++i) {
00681                     QPointF cp1 = offsetCurves[i].pt2();
00682                     QPointF cp2 = offsetCurves[i].pt3();
00683                     QPointF ep = offsetCurves[i].pt4();
00684                     stroker->emitCubicTo(qt_real_to_fixed(cp1.x()), qt_real_to_fixed(cp1.y()),
00685                                          qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),
00686                                          qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));
00687                 }
00688             }
00689 
00690             prev = ep;
00691         }
00692     }
00693 
00694     if (start == prev) {
00695         // closed subpath, join first and last point
00696 #ifdef QPP_STROKE_DEBUG
00697         qDebug("\n ---> (side) closed subpath");
00698 #endif
00699         stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
00700         return true;
00701     } else {
00702 #ifdef QPP_STROKE_DEBUG
00703         qDebug("\n ---> (side) open subpath");
00704 #endif
00705         return false;
00706     }
00707 }

Here is the call graph for this function:


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