📄 qstroker.cpp
字号:
} } begin(data); moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y())); for (int i=0; i<12; i+=3) { cubicTo(qt_real_to_fixed(pts[i].x()), qt_real_to_fixed(pts[i].y()), qt_real_to_fixed(pts[i+1].x()), qt_real_to_fixed(pts[i+1].y()), qt_real_to_fixed(pts[i+2].x()), qt_real_to_fixed(pts[i+2].y())); } end();}QStroker::QStroker() : m_capStyle(SquareJoin), m_joinStyle(FlatJoin), m_back1X(0), m_back1Y(0), m_back2X(0), m_back2Y(0){ m_strokeWidth = qt_real_to_fixed(1); m_miterLimit = qt_real_to_fixed(2); m_curveThreshold = qt_real_to_fixed(0.25);}QStroker::~QStroker(){}Qt::PenCapStyle QStroker::capForJoinMode(LineJoinMode mode){ if (mode == FlatJoin) return Qt::FlatCap; else if (mode == SquareJoin) return Qt::SquareCap; else return Qt::RoundCap;}QStroker::LineJoinMode QStroker::joinModeForCap(Qt::PenCapStyle style){ if (style == Qt::FlatCap) return FlatJoin; else if (style == Qt::SquareCap) return SquareJoin; else return RoundCap;}Qt::PenJoinStyle QStroker::joinForJoinMode(LineJoinMode mode){ if (mode == FlatJoin) return Qt::BevelJoin; else if (mode == MiterJoin) return Qt::MiterJoin; else if (mode == SvgMiterJoin) return Qt::SvgMiterJoin; else return Qt::RoundJoin;}QStroker::LineJoinMode QStroker::joinModeForJoin(Qt::PenJoinStyle joinStyle){ if (joinStyle == Qt::BevelJoin) return FlatJoin; else if (joinStyle == Qt::MiterJoin) return MiterJoin; else if (joinStyle == Qt::SvgMiterJoin) return SvgMiterJoin; else return RoundJoin;}/*! This function is called to stroke the currently built up subpath. The subpath is cleared when the function completes.*/void QStroker::processCurrentSubpath(){ Q_ASSERT(!m_elements.isEmpty()); Q_ASSERT(m_elements.first().type == QPainterPath::MoveToElement); Q_ASSERT(m_elements.size() > 1); QSubpathForwardIterator fwit(&m_elements); QSubpathBackwardIterator bwit(&m_elements); QLineF fwStartTangent, bwStartTangent; bool fwclosed = qt_stroke_side(&fwit, this, false, &fwStartTangent); bool bwclosed = qt_stroke_side(&bwit, this, !fwclosed, &bwStartTangent); if (!bwclosed) joinPoints(m_elements.at(0).x, m_elements.at(0).y, fwStartTangent, m_capStyle);}/*! \internal*/void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine, LineJoinMode join){#ifdef QPP_STROKE_DEBUG printf(" -----> joinPoints: around=(%.0f, %.0f), next_p1=(%.0f, %.f) next_p2=(%.0f, %.f)\n", qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y), nextLine.x1(), nextLine.y1(), nextLine.x2(), nextLine.y2());#endif // points connected already, don't join#if !defined (QFIXED_26_6) && !defined (Q_FIXED_32_32) if (qFuzzyCompare(m_back1X, nextLine.x1()) && qFuzzyCompare(m_back1Y, nextLine.y1())) return;#else if (m_back1X == qt_real_to_fixed(nextLine.x1()) && m_back1Y == qt_real_to_fixed(nextLine.y1())) { return; }#endif if (join == FlatJoin) { emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); } else { QLineF prevLine(qt_fixed_to_real(m_back2X), qt_fixed_to_real(m_back2Y), qt_fixed_to_real(m_back1X), qt_fixed_to_real(m_back1Y)); QPointF isect; QLineF::IntersectType type = prevLine.intersect(nextLine, &isect); if (join == MiterJoin) { qreal appliedMiterLimit = qt_fixed_to_real(m_strokeWidth * m_miterLimit); // If we are on the inside, do the short cut... QLineF shortCut(prevLine.p2(), nextLine.p1()); qreal angle = prevLine.angle(shortCut); if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) { emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); return; } QLineF miterLine(QPointF(qt_fixed_to_real(m_back1X), qt_fixed_to_real(m_back1Y)), isect); if (type == QLineF::NoIntersection || miterLine.length() > appliedMiterLimit) { QLineF l1(prevLine); l1.setLength(appliedMiterLimit); l1.translate(prevLine.dx(), prevLine.dy()); QLineF l2(nextLine); l2.setLength(appliedMiterLimit); l2.translate(-l2.dx(), -l2.dy()); emitLineTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2())); emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1())); emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); } else { emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y())); emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); } } else if (join == SquareJoin) { qfixed offset = m_strokeWidth / 2; QLineF l1(prevLine); l1.translate(l1.dx(), l1.dy()); l1.setLength(qt_fixed_to_real(offset)); QLineF l2(nextLine.p2(), nextLine.p1()); l2.translate(l2.dx(), l2.dy()); l2.setLength(qt_fixed_to_real(offset)); emitLineTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2())); emitLineTo(qt_real_to_fixed(l2.x2()), qt_real_to_fixed(l2.y2())); emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1())); } else if (join == RoundJoin) { qfixed offset = m_strokeWidth / 2; QLineF shortCut(prevLine.p2(), nextLine.p1()); qreal angle = prevLine.angle(shortCut); if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) { emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); return; } qreal l1_on_x = adapted_angle_on_x(prevLine); qreal l2_on_x = adapted_angle_on_x(nextLine); qreal sweepLength = qAbs(l2_on_x - l1_on_x); int point_count; QPointF curves[12]; QPointF curve_start = qt_curves_for_arc(QRectF(qt_fixed_to_real(focal_x - offset), qt_fixed_to_real(focal_y - offset), qt_fixed_to_real(offset * 2), qt_fixed_to_real(offset * 2)), l1_on_x + 90, -sweepLength, curves, &point_count);// // line to the beginning of the arc segment, (should not be needed).// emitLineTo(qt_real_to_fixed(curve_start.x()), qt_real_to_fixed(curve_start.y())); for (int i=0; i<point_count; i+=3) { emitCubicTo(qt_real_to_fixed(curves[i].x()), qt_real_to_fixed(curves[i].y()), qt_real_to_fixed(curves[i+1].x()), qt_real_to_fixed(curves[i+1].y()), qt_real_to_fixed(curves[i+2].x()), qt_real_to_fixed(curves[i+2].y())); } // line to the end of the arc segment, (should also not be needed). emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); // Same as round join except we know its 180 degrees. Can also optimize this // later based on the addEllipse logic } else if (join == RoundCap) { qfixed offset = m_strokeWidth / 2; // first control line QLineF l1 = prevLine; l1.translate(l1.dx(), l1.dy()); l1.setLength(QT_PATH_KAPPA * offset); // second control line, find through normal between prevLine and focal. QLineF l2(qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y), prevLine.x2(), prevLine.y2()); l2.translate(-l2.dy(), l2.dx()); l2.setLength(QT_PATH_KAPPA * offset); emitCubicTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2()), qt_real_to_fixed(l2.x2()), qt_real_to_fixed(l2.y2()), qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1())); // move so that it matches l2 = QLineF(l2.x1(), l2.y1(), l2.x1()-l2.dx(), l2.y1()-l2.dy()); // last line is parallel to l1 so just shift it down. l1.translate(nextLine.x1() - l1.x1(), nextLine.y1() - l1.y1()); emitCubicTo(qt_real_to_fixed(l2.x2()), qt_real_to_fixed(l2.y2()), qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2()), qt_real_to_fixed(l1.x1()), qt_real_to_fixed(l1.y1())); } else if (join == SvgMiterJoin) { QLineF miterLine(QPointF(qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y)), isect); if (miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) { emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); } else { emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y())); emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); } } else { qFatal("QStroker::joinPoints(), bad join style..."); } }}/* Strokes a subpath side using the \a it as source. Results are put into \a stroke. The function returns true if the subpath side was closed. If \a capFirst is true, we will use capPoints instead of joinPoints to connect the first segment, other segments will be joined using joinPoints. This is to put capping in order...*/template <class Iterator> bool qt_stroke_side(Iterator *it, QStroker *stroker, bool capFirst, QLineF *startTangent){ // Used in CurveToElement section below. const int MAX_OFFSET = 16; QBezier offsetCurves[MAX_OFFSET]; Q_ASSERT(it->hasNext()); // The initaial move to QStrokerOps::Element first_element = it->next(); Q_ASSERT(first_element.isMoveTo()); qfixed2d start = first_element;#ifdef QPP_STROKE_DEBUG qDebug(" -> (side) [%.2f, %.2f], startPos=%d", qt_fixed_to_real(start.x), qt_fixed_to_real(start.y));#endif qfixed2d prev = start; bool first = true; qfixed offset = stroker->strokeWidth() / 2; while (it->hasNext()) { QStrokerOps::Element e = it->next(); // LineToElement if (e.isLineTo()) {#ifdef QPP_STROKE_DEBUG qDebug("\n ---> (side) lineto [%.2f, %.2f]", e.x, e.y);#endif QLineF line(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y), qt_fixed_to_real(e.x), qt_fixed_to_real(e.y)); QLineF normal = line.normalVector(); normal.setLength(offset); line.translate(normal.dx(), normal.dy()); // If we are starting a new subpath, move to correct starting point. if (first) { if (capFirst) stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode()); else stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1())); *startTangent = line; first = false; } else { stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode()); } // Add the stroke for this line. stroker->emitLineTo(qt_real_to_fixed(line.x2()), qt_real_to_fixed(line.y2())); prev = e; // CurveToElement } else if (e.isCurveTo()) { QStrokerOps::Element cp2 = it->next(); // control point 2 QStrokerOps::Element ep = it->next(); // end point#ifdef QPP_STROKE_DEBUG qDebug("\n ---> (side) cubicTo [%.2f, %.2f]", qt_fixed_to_real(ep.x), qt_fixed_to_real(ep.y));#endif QBezier bezier = QBezier::fromPoints(QPointF(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y)), QPointF(qt_fixed_to_real(e.x), qt_fixed_to_real(e.y)), QPointF(qt_fixed_to_real(cp2.x), qt_fixed_to_real(cp2.y)), QPointF(qt_fixed_to_real(ep.x), qt_fixed_to_real(ep.y))); int count = bezier.shifted(offsetCurves, MAX_OFFSET, offset, stroker->curveThreshold()); if (count) { // If we are starting a new subpath, move to correct starting point QLineF tangent = offsetCurves[0].startTangent();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -