⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qpathclipper.cpp

📁 奇趣公司比较新的qt/emd版本
💻 CPP
📖 第 1 页 / 共 3 页
字号:
                    Line line(QLineF(last, path.elementAt(i+2)));                    m_lines << line;                } else {                    m_beziers << bezier;                }            }            last = path.elementAt(i + 2);            i += 2;            break;        default:            Q_ASSERT(false);            break;        }    }    if (hasMoveTo && last != lastMoveTo) {        Line line(QLineF(last, lastMoveTo), true);        m_lines << line;    }}qreal QWingedEdge::delta(int vertex, int a, int b) const{    const QPathEdge *ap = edge(a);    const QPathEdge *bp = edge(b);    qreal a_angle = ap->angle;    qreal b_angle = bp->angle;    if (vertex == ap->second)        a_angle = ap->invAngle;    if (vertex == bp->second)        b_angle = bp->invAngle;    qreal result = b_angle - a_angle;    if (qFuzzyCompare(result, qreal(0)) || qFuzzyCompare(result, qreal(128)))        return 0;    if (result < 0)        return result + 128.;    else        return result;}static inline QPointF tangentAt(const QWingedEdge &list, int vi, int ei){    const QPathEdge *ep = list.edge(ei);    Q_ASSERT(ep);    qreal t;    qreal sign;    if (ep->first == vi) {        t = ep->t0;        sign = 1;    } else {        t = ep->t1;        sign = -1;    }    QPointF normal;    if (ep->bezier) {        normal = ep->bezier->derivedAt(t);        if (normal == QPointF())            normal = ep->bezier->secondDerivedAt(t);    } else {        const QPointF a = *list.vertex(ep->first);        const QPointF b = *list.vertex(ep->second);        normal = b - a;    }    return normalize(sign * normal);}static inline QPointF midPoint(const QWingedEdge &list, int ei){    const QPathEdge *ep = list.edge(ei);    Q_ASSERT(ep);    if (ep->bezier) {        return ep->bezier->pointAt(0.5 * (ep->t0 + ep->t1));    } else {        const QPointF a = *list.vertex(ep->first);        const QPointF b = *list.vertex(ep->second);        return a + 0.5 * (b - a);    }}static QBezier transform(const QBezier &bezier, const QPointF &xAxis, const QPointF &yAxis, const QPointF &origin){    QPointF points[4] = {        bezier.pt1(),        bezier.pt2(),        bezier.pt3(),        bezier.pt4()    };    for (int i = 0; i < 4; ++i) {        const QPointF p = points[i] - origin;        points[i].rx() = dot(xAxis, p);        points[i].ry() = dot(yAxis, p);    }    return QBezier::fromPoints(points[0], points[1], points[2], points[3]);}static bool isLeftOf(const QWingedEdge &list, int vi, int ai, int bi){    const QPathEdge *ap = list.edge(ai);    const QPathEdge *bp = list.edge(bi);    Q_ASSERT(ap);    Q_ASSERT(bp);    // shouldn't have two line segments with same normal    // (they should have been merged during winged edge construction)    Q_ASSERT(ap->bezier || bp->bezier);    const QPointF tangent = tangentAt(list, vi, ai);    const QPointF normal(tangent.y(), -tangent.x());    const QPointF origin = *list.vertex(vi);    const QPointF dpA = midPoint(list, ai) - origin;    const QPointF dpB = midPoint(list, bi) - origin;    qreal xA = dot(normal, dpA);    qreal xB = dot(normal, dpB);    if (xA <= 0 && xB >= 0)        return true;    if (xA >= 0 && xB <= 0)        return false;    if (!ap->bezier)        return xB > 0;    if (!bp->bezier)        return xA < 0;    // both are beziers on the same side of the tangent    // transform the beziers into the local coordinate system    // such that positive y is along the tangent, and positive x is along the normal    QBezier bezierA = transform(*ap->bezier, normal, tangent, origin);    QBezier bezierB = transform(*bp->bezier, normal, tangent, origin);    qreal y = qMin(bezierA.pointAt(0.5 * (ap->t0 + ap->t1)).y(),                   bezierB.pointAt(0.5 * (bp->t0 + bp->t1)).y());    xA = bezierA.pointAt(bezierA.tForY(ap->t0, ap->t1, y)).x();    xB = bezierB.pointAt(bezierB.tForY(bp->t0, bp->t1, y)).x();    return xA < xB;}QWingedEdge::TraversalStatus QWingedEdge::findInsertStatus(int vi, int ei) const{    const QPathVertex *vp = vertex(vi);    Q_ASSERT(vp);    Q_ASSERT(ei >= 0);    Q_ASSERT(vp->edge >= 0);    int position = vp->edge;    qreal d = 128.;    TraversalStatus status;    status.direction = edge(vp->edge)->directionTo(vi);    status.traversal = QPathEdge::RightTraversal;    status.edge = vp->edge;#ifdef QDEBUG_CLIPPER    const QPathEdge *ep = edge(ei);    qDebug() << "Finding insert status for edge" << ei << "at vertex" << QPointF(*vp) << ", angles: " << ep->angle << ep->invAngle;#endif    do {        status = next(status);        status.flip();        Q_ASSERT(edge(status.edge)->vertex(status.direction) == vi);        qreal d2 = delta(vi, ei, status.edge);#ifdef QDEBUG_CLIPPER        const QPathEdge *op = edge(status.edge);        qDebug() << "Delta to edge" << status.edge << d2 << ", angles: " << op->angle << op->invAngle;#endif        if (!(qFuzzyCompare(d2, 0) && isLeftOf(*this, vi, status.edge, ei))            && (d2 < d || qFuzzyCompare(d2, d) && isLeftOf(*this, vi, status.edge, position))) {            position = status.edge;            d = d2;        }    } while (status.edge != vp->edge);    status.traversal = QPathEdge::LeftTraversal;    status.direction = QPathEdge::Forward;    status.edge = position;    if (edge(status.edge)->vertex(status.direction) != vi)        status.flip();#ifdef QDEBUG_CLIPPER    qDebug() << "Inserting edge" << ei << "to" << (status.traversal == QPathEdge::LeftTraversal ? "left" : "right") << "of edge" << status.edge;#endif    Q_ASSERT(edge(status.edge)->vertex(status.direction) == vi);    return status;}void QWingedEdge::removeEdge(int ei){    QPathEdge *ep = edge(ei);    TraversalStatus status;    status.direction = QPathEdge::Forward;    status.traversal = QPathEdge::RightTraversal;    status.edge = ei;    TraversalStatus forwardRight = next(status);    forwardRight.flipDirection();    status.traversal = QPathEdge::LeftTraversal;    TraversalStatus forwardLeft = next(status);    forwardLeft.flipDirection();    status.direction = QPathEdge::Backward;    TraversalStatus backwardLeft = next(status);    backwardLeft.flipDirection();    status.traversal = QPathEdge::RightTraversal;    TraversalStatus backwardRight = next(status);    backwardRight.flipDirection();    edge(forwardRight.edge)->setNext(forwardRight.traversal, forwardRight.direction, forwardLeft.edge);    edge(forwardLeft.edge)->setNext(forwardLeft.traversal, forwardLeft.direction, forwardRight.edge);    edge(backwardRight.edge)->setNext(backwardRight.traversal, backwardRight.direction, backwardLeft.edge);    edge(backwardLeft.edge)->setNext(backwardLeft.traversal, backwardLeft.direction, backwardRight.edge);    ep->setNext(QPathEdge::Forward, ei);    ep->setNext(QPathEdge::Backward, ei);    QPathVertex *a = vertex(ep->first);    QPathVertex *b = vertex(ep->second);    a->edge = backwardRight.edge;    b->edge = forwardRight.edge;}static int commonEdge(const QWingedEdge &list, int a, int b){    const QPathVertex *ap = list.vertex(a);    Q_ASSERT(ap);    const QPathVertex *bp = list.vertex(b);    Q_ASSERT(bp);    if (ap->edge < 0 || bp->edge < 0)        return -1;    QWingedEdge::TraversalStatus status;    status.edge = ap->edge;    status.direction = list.edge(status.edge)->directionTo(a);    status.traversal = QPathEdge::RightTraversal;    do {        const QPathEdge *ep = list.edge(status.edge);        if (ep->first == a && ep->second == b ||            ep->first == b && ep->second == a)            return status.edge;        status = list.next(status);        status.flip();    } while (status.edge != ap->edge);    return -1;}static qreal computeAngle(const QPointF &v){#if 1    if (v.x() == 0) {        return v.y() <= 0 ? 0 : 64.;    } else if (v.y() == 0) {        return v.x() <= 0 ? 32. : 96.;    }    QPointF nv = normalize(v);    if (nv.y() < 0) {        if (nv.x() < 0) { // 0 - 32            return -32. * nv.x();        } else { // 96 - 128            return 128. - 32. * nv.x();        }    } else { // 32 - 96        return 64. + 32 * nv.x();    }#else    // doesn't seem to be robust enough    return atan2(v.x(), v.y()) + Q_PI;#endif}int QWingedEdge::addEdge(const QPointF &a, const QPointF &b, const QBezier *bezier, qreal t0, qreal t1){    int fi = insert(a);    int si = insert(b);    if (fi == si)        return -1;    int common = commonEdge(*this, fi, si);    if (common >= 0)        return common;    m_edges << QPathEdge(fi, si);    int ei = m_edges.size() - 1;    QPathVertex *fp = vertex(fi);    QPathVertex *sp = vertex(si);    QPathEdge *ep = edge(ei);    ep->bezier = bezier;    ep->t0 = t0;    ep->t1 = t1;    if (bezier) {        QPointF aTangent = bezier->derivedAt(t0);        QPointF bTangent = bezier->derivedAt(t1);        if (aTangent == QPointF())            aTangent = bezier->secondDerivedAt(t0);        if (bTangent == QPointF())            bTangent = bezier->secondDerivedAt(t1);        ep->angle = computeAngle(aTangent);        ep->invAngle = computeAngle(-bTangent);    } else {        const QPointF tangent = b - a;        ep->angle = computeAngle(tangent);        ep->invAngle = computeAngle(-tangent);    }    QPathVertex *vertices[2] = { fp, sp };    QPathEdge::Direction dirs[2] = { QPathEdge::Backward, QPathEdge::Forward };#ifdef QDEBUG_CLIPPER    qDebug() << "** Adding edge" << ei << "/ vertices:" << a << b;#endif    for (int i = 0; i < 2; ++i) {        QPathVertex *vp = vertices[i];        if (vp->edge < 0) {            vp->edge = ei;            ep->setNext(dirs[i], ei);        } else {            int vi = ep->vertex(dirs[i]);            Q_ASSERT(vertex(vi) == vertices[i]);            TraversalStatus os = findInsertStatus(vi, ei);            QPathEdge *op = edge(os.edge);            Q_ASSERT(vertex(op->vertex(os.direction)) == vertices[i]);            TraversalStatus ns = next(os);            ns.flipDirection();            QPathEdge *np = edge(ns.edge);            op->setNext(os.traversal, os.direction, ei);            np->setNext(ns.traversal, ns.direction, ei);            int oe = os.edge;            int ne = ns.edge;            os = next(os);            ns = next(ns);            os.flipDirection();            ns.flipDirection();            Q_ASSERT(os.edge == ei);            Q_ASSERT(ns.edge == ei);            ep->setNext(os.traversal, os.direction, oe);            ep->setNext(ns.traversal, ns.direction, ne);        }    }    Q_ASSERT(ep->next(QPathEdge::RightTraversal, QPathEdge::Forward) >= 0);    Q_ASSERT(ep->next(QPathEdge::RightTraversal, QPathEdge::Backward) >= 0);    Q_ASSERT(ep->next(QPathEdge::LeftTraversal, QPathEdge::Forward) >= 0);    Q_ASSERT(ep->next(QPathEdge::LeftTraversal, QPathEdge::Backward) >= 0);    return ei;}void QWingedEdge::addBezierEdge(const QBezier *bezier, const QPointF &a, const QPointF &b, qreal alphaA, qreal alphaB, int path){    if (qFuzzyCompare(alphaA, alphaB))        return;    qreal alphaMid = (alphaA + alphaB) * 0.5;    qreal s0 = 0;    qreal s1 = 1;    int count = bezier->stationaryYPoints(s0, s1);    m_splitPoints.clear();    m_splitPoints << alphaA;    m_splitPoints << alphaMid;    m_splitPoints << alphaB;    if (count > 0 && !qFuzzyCompare(s0, alphaA) && !qFuzzyCompare(s0, alphaMid) && !qFuzzyCompare(s0, alphaB) && s0 > alphaA && s0 < alphaB)        m_splitPoints << s0;    if (count > 1 && !qFuzzyCompare(s1, alphaA) && !qFuzzyCompare(s1, alphaMid) && !qFuzzyCompare(s1, alphaB) && s1 > alphaA && s1 < alphaB)        m_splitPoints << s1;    if (count > 0)        qSort(m_splitPoints.begin(), m_splitPoints.end());    QPointF pa = a;    for (int i = 0; i < m_splitPoints.size() - 1; ++i) {        const qreal t0 = m_splitPoints[i];        const qreal t1 = m_splitPoints[i+1];        const QPointF pb = (i + 1) == (m_splitPoints.size() - 1) ? b : bezier->pointAt(t1);        QPathEdge *ep = edge(addEdge(pa, pb, bezier, t0, t1));        if (ep) {            const int dir = pa.y() < pb.y() ? 1 : -1;            if (path == 0)                ep->windingA += dir;            else                ep->windingB += dir;        }        pa = pb;    }}int QWingedEdge::insert(const QPathVertex &vertex){    if (!m_vertices.isEmpty()) {        const QPathVertex &last = m_vertices.last();        if (vertex.x == last.x && vertex.y == last.y)            return m_vertices.size() - 1;        for (int i = 0; i < m_vertices.size(); ++i) {            const QPathVertex &v = m_vertices.at(i);            if (qFuzzyCompare(v.x, vertex.x) && qFuzzyCompare(v.y, vertex.y)) {                return i;            }        }    }    m_vertices << vertex;    return m_vertices.size() - 1;}static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal){    QWingedEdge::TraversalStatus status;    status.edge = edge;    status.traversal = traversal;    status.direction = QPathEdge::Forward;    const QBezier *bezier = 0;    qreal t0 = 1;    qreal t1 = 0;    bool forward = true;    path.moveTo(*list.vertex(list.edge(edge)->first));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -