Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/skia/skia/src/core/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 25 kB image not shown  

Quelle  SkContourMeasure.cpp   Sprache: C

 
/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "include/core/SkContourMeasure.h"

#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkGeometry.h"
#include "src/core/SkPathMeasurePriv.h"
#include "src/core/SkPathPriv.h"

#include <algorithm>
#include <array>
#include <cstddef>
#include <utility>

#define kMaxTValue  0x3FFFFFFF

constexpr static inline SkScalar tValue2Scalar(int t) {
    SkASSERT((unsigned)t <= kMaxTValue);
    // 1/kMaxTValue can't be represented as a float, but it's close and the limits work fine.
    const SkScalar kMaxTReciprocal = 1.0f / (SkScalar)kMaxTValue;
    return t * kMaxTReciprocal;
}

static_assert(0.0f == tValue2Scalar(         0), "Lower limit should be exact.");
static_assert(1.0f == tValue2Scalar(kMaxTValue), "Upper limit should be exact.");

SkScalar SkContourMeasure::Segment::getScalarT() const {
    return tValue2Scalar(fTValue);
}

void SkContourMeasure_segTo(const SkPoint pts[], unsigned segType,
                            SkScalar startT, SkScalar stopT, SkPath* dst) {
    SkASSERT(startT >= 0 && startT <= SK_Scalar1);
    SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
    SkASSERT(startT <= stopT);

    if (startT == stopT) {
        if (!dst->isEmpty()) {
            /* if the dash as a zero-length on segment, add a corresponding zero-length line.
               The stroke code will add end caps to zero length lines as appropriate */

            SkPoint lastPt;
            SkAssertResult(dst->getLastPt(&lastPt));
            dst->lineTo(lastPt);
        }
        return;
    }

    SkPoint tmp0[7], tmp1[7];

    switch (segType) {
        case kLine_SegType:
            if (SK_Scalar1 == stopT) {
                dst->lineTo(pts[1]);
            } else {
                dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
                            SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
            }
            break;
        case kQuad_SegType:
            if (0 == startT) {
                if (SK_Scalar1 == stopT) {
                    dst->quadTo(pts[1], pts[2]);
                } else {
                    SkChopQuadAt(pts, tmp0, stopT);
                    dst->quadTo(tmp0[1], tmp0[2]);
                }
            } else {
                SkChopQuadAt(pts, tmp0, startT);
                if (SK_Scalar1 == stopT) {
                    dst->quadTo(tmp0[3], tmp0[4]);
                } else {
                    SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT));
                    dst->quadTo(tmp1[1], tmp1[2]);
                }
            }
            break;
        case kConic_SegType: {
            SkConic conic(pts[0], pts[2], pts[3], pts[1].fX);

            if (0 == startT) {
                if (SK_Scalar1 == stopT) {
                    dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
                } else {
                    SkConic tmp[2];
                    if (conic.chopAt(stopT, tmp)) {
                        dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW);
                    }
                }
            } else {
                if (SK_Scalar1 == stopT) {
                    SkConic tmp[2];
                    if (conic.chopAt(startT, tmp)) {
                        dst->conicTo(tmp[1].fPts[1], tmp[1].fPts[2], tmp[1].fW);
                    }
                } else {
                    SkConic tmp;
                    conic.chopAt(startT, stopT, &tmp);
                    dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW);
                }
            }
        } break;
        case kCubic_SegType:
            if (0 == startT) {
                if (SK_Scalar1 == stopT) {
                    dst->cubicTo(pts[1], pts[2], pts[3]);
                } else {
                    SkChopCubicAt(pts, tmp0, stopT);
                    dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
                }
            } else {
                SkChopCubicAt(pts, tmp0, startT);
                if (SK_Scalar1 == stopT) {
                    dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
                } else {
                    SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT));
                    dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
                }
            }
            break;
        default:
            SK_ABORT("unknown segType");
    }
}

///////////////////////////////////////////////////////////////////////////////

static inline int tspan_big_enough(int tspan) {
    SkASSERT((unsigned)tspan <= kMaxTValue);
    return tspan >> 10;
}

// can't use tangents, since we need [0..1..................2] to be seen
// as definitely not a line (it is when drawn, but not parametrically)
// so we compare midpoints
#define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up

static bool quad_too_curvy(const SkPoint pts[3], SkScalar tolerance) {
    // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
    // diff = -a/4 + b/2 - c/4
    SkScalar dx = SkScalarHalf(pts[1].fX) -
                        SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
    SkScalar dy = SkScalarHalf(pts[1].fY) -
                        SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));

    SkScalar dist = std::max(SkScalarAbs(dx), SkScalarAbs(dy));
    return dist > tolerance;
}

static bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,
                            const SkPoint& lastPt, SkScalar tolerance) {
    SkPoint midEnds = firstPt + lastPt;
    midEnds *= 0.5f;
    SkVector dxy = midTPt - midEnds;
    SkScalar dist = std::max(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY));
    return dist > tolerance;
}

static bool cheap_dist_exceeds_limit(const SkPoint& pt, SkScalar x, SkScalar y,
                                     SkScalar tolerance) {
    SkScalar dist = std::max(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
    // just made up the 1/2
    return dist > tolerance;
}

static bool cubic_too_curvy(const SkPoint pts[4], SkScalar tolerance) {
    return  cheap_dist_exceeds_limit(pts[1],
                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3), tolerance)
                         ||
            cheap_dist_exceeds_limit(pts[2],
                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3), tolerance);
}

// puts a cap on the total size of our output, since the client can pass in
// arbitrarily large values for resScale.
constexpr int kMaxRecursionDepth = 8;

class SkContourMeasureIter::Impl {
public:
    Impl(const SkPath& path, bool forceClosed, SkScalar resScale)
        : fPath(path)
        , fIter(SkPathPriv::Iterate(fPath).begin())
        , fTolerance(CHEAP_DIST_LIMIT * sk_ieee_float_divide(1.0f, resScale))
        , fForceClosed(forceClosed) {}

    bool hasNextSegments() const { return fIter != SkPathPriv::Iterate(fPath).end(); }
    SkContourMeasure* buildSegments();

private:
    SkPath                fPath;
    SkPathPriv::RangeIter fIter;
    SkScalar              fTolerance;
    bool                  fForceClosed;

    // temporary
    SkTDArray<SkContourMeasure::Segment>  fSegments;
    SkTDArray<SkPoint>  fPts; // Points used to define the segments

    SkDEBUGCODE(void validate() const;)
    SkScalar compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance, unsigned ptIndex);
    SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance,
                               int mint, int maxt, unsigned ptIndex, int recursionDepth = 0);
    SkScalar compute_conic_segs(const SkConic& conic, SkScalar distance,
                                                         int mint, const SkPoint& minPt,
                                                         int maxt, const SkPoint& maxPt,
                                unsigned ptIndex, int recursionDepth = 0);
    SkScalar compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
                                int mint, int maxt, unsigned ptIndex, int recursionDepth = 0);
};

SkScalar SkContourMeasureIter::Impl::compute_quad_segs(const SkPoint pts[3], SkScalar distance,
                                                       int mint, int maxt, unsigned ptIndex,
                                                       int recursionDepth) {
    if (recursionDepth < kMaxRecursionDepth &&
        tspan_big_enough(maxt - mint) && quad_too_curvy(pts, fTolerance)) {
        SkPoint tmp[5];
        int     halft = (mint + maxt) >> 1;

        SkChopQuadAtHalf(pts, tmp);
        recursionDepth += 1;
        distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex, recursionDepth);
        distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex, recursionDepth);
    } else {
        SkScalar d = SkPoint::Distance(pts[0], pts[2]);
        SkScalar prevD = distance;
        distance += d;
        if (distance > prevD) {
            SkASSERT(ptIndex < (unsigned)fPts.size());
            SkContourMeasure::Segment* seg = fSegments.append();
            seg->fDistance = distance;
            seg->fPtIndex = ptIndex;
            seg->fType = kQuad_SegType;
            seg->fTValue = maxt;
        }
    }
    return distance;
}

SkScalar SkContourMeasureIter::Impl::compute_conic_segs(const SkConic& conic, SkScalar distance,
                                                        int mint, const SkPoint& minPt,
                                                        int maxt, const SkPoint& maxPt,
                                                        unsigned ptIndex, int recursionDepth) {
    int halft = (mint + maxt) >> 1;
    SkPoint halfPt = conic.evalAt(tValue2Scalar(halft));
    if (!halfPt.isFinite()) {
        return distance;
    }
    if (recursionDepth < kMaxRecursionDepth &&
        tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt, fTolerance))
    {
        recursionDepth += 1;
        distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt,
                                            ptIndex, recursionDepth);
        distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt,
                                            ptIndex, recursionDepth);
    } else {
        SkScalar d = SkPoint::Distance(minPt, maxPt);
        SkScalar prevD = distance;
        distance += d;
        if (distance > prevD) {
            SkASSERT(ptIndex < (unsigned)fPts.size());
            SkContourMeasure::Segment* seg = fSegments.append();
            seg->fDistance = distance;
            seg->fPtIndex = ptIndex;
            seg->fType = kConic_SegType;
            seg->fTValue = maxt;
        }
    }
    return distance;
}

SkScalar SkContourMeasureIter::Impl::compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
                                                        int mint, int maxt, unsigned ptIndex,
                                                        int recursionDepth) {
    if (recursionDepth < kMaxRecursionDepth &&
        tspan_big_enough(maxt - mint) && cubic_too_curvy(pts, fTolerance))
    {
        SkPoint tmp[7];
        int     halft = (mint + maxt) >> 1;

        SkChopCubicAtHalf(pts, tmp);
        recursionDepth += 1;
        distance = this->compute_cubic_segs(tmp, distance, mint, halft,
                                            ptIndex, recursionDepth);
        distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt,
                                            ptIndex, recursionDepth);
    } else {
        SkScalar d = SkPoint::Distance(pts[0], pts[3]);
        SkScalar prevD = distance;
        distance += d;
        if (distance > prevD) {
            SkASSERT(ptIndex < (unsigned)fPts.size());
            SkContourMeasure::Segment* seg = fSegments.append();
            seg->fDistance = distance;
            seg->fPtIndex = ptIndex;
            seg->fType = kCubic_SegType;
            seg->fTValue = maxt;
        }
    }
    return distance;
}

SkScalar SkContourMeasureIter::Impl::compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance,
                                                      unsigned ptIndex) {
    SkScalar d = SkPoint::Distance(p0, p1);
    SkASSERT(d >= 0);
    SkScalar prevD = distance;
    distance += d;
    if (distance > prevD) {
        SkASSERT((unsigned)ptIndex < (unsigned)fPts.size());
        SkContourMeasure::Segment* seg = fSegments.append();
        seg->fDistance = distance;
        seg->fPtIndex = ptIndex;
        seg->fType = kLine_SegType;
        seg->fTValue = kMaxTValue;
    }
    return distance;
}

#ifdef SK_DEBUG
void SkContourMeasureIter::Impl::validate() const {
#ifndef SK_DISABLE_SLOW_DEBUG_VALIDATION
    const SkContourMeasure::Segment* seg = fSegments.begin();
    const SkContourMeasure::Segment* stop = fSegments.end();
    unsigned ptIndex = 0;
    SkScalar distance = 0;
    // limit the loop to a reasonable number; pathological cases can run for minutes
    int maxChecks = 10000000;  // set to INT_MAX to defeat the check
    while (seg < stop) {
        SkASSERT(seg->fDistance > distance);
        SkASSERT(seg->fPtIndex >= ptIndex);
        SkASSERT(seg->fTValue > 0);

        const SkContourMeasure::Segment* s = seg;
        while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) {
            SkASSERT(s[0].fType == s[1].fType);
            SkASSERT(s[0].fTValue < s[1].fTValue);
            s += 1;
        }

        distance = seg->fDistance;
        ptIndex = seg->fPtIndex;
        seg += 1;
    }
#endif
}
#endif

SkContourMeasure* SkContourMeasureIter::Impl::buildSegments() {
    int         ptIndex = -1;
    SkScalar    distance = 0;
    bool        haveSeenClose = fForceClosed;
    bool        haveSeenMoveTo = false;

    /*  Note:
     *  as we accumulate distance, we have to check that the result of +=
     *  actually made it larger, since a very small delta might be > 0, but
     *  still have no effect on distance (if distance >>> delta).
     *
     *  We do this check below, and in compute_quad_segs and compute_cubic_segs
     */


    fSegments.reset();
    fPts.reset();

    auto end = SkPathPriv::Iterate(fPath).end();
    for (; fIter != end; ++fIter) {
        auto [verb, pts, w] = *fIter;
        if (haveSeenMoveTo && verb == SkPathVerb::kMove) {
            break;
        }
        switch (verb) {
            case SkPathVerb::kMove:
                ptIndex += 1;
                fPts.append(1, pts);
                SkASSERT(!haveSeenMoveTo);
                haveSeenMoveTo = true;
                break;

            case SkPathVerb::kLine: {
                SkASSERT(haveSeenMoveTo);
                SkScalar prevD = distance;
                distance = this->compute_line_seg(pts[0], pts[1], distance, ptIndex);
                if (distance > prevD) {
                    fPts.append(1, pts + 1);
                    ptIndex++;
                }
            } break;

            case SkPathVerb::kQuad: {
                SkASSERT(haveSeenMoveTo);
                SkScalar prevD = distance;
                distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex);
                if (distance > prevD) {
                    fPts.append(2, pts + 1);
                    ptIndex += 2;
                }
            } break;

            case SkPathVerb::kConic: {
                SkASSERT(haveSeenMoveTo);
                const SkConic conic(pts, *w);
                SkScalar prevD = distance;
                distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0],
                                                    kMaxTValue, conic.fPts[2], ptIndex);
                if (distance > prevD) {
                    // we store the conic weight in our next point, followed by the last 2 pts
                    // thus to reconstitue a conic, you'd need to say
                    // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX)
                    fPts.append()->set(conic.fW, 0);
                    fPts.append(2, pts + 1);
                    ptIndex += 3;
                }
            } break;

            case SkPathVerb::kCubic: {
                SkASSERT(haveSeenMoveTo);
                SkScalar prevD = distance;
                distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex);
                if (distance > prevD) {
                    fPts.append(3, pts + 1);
                    ptIndex += 3;
                }
            } break;

            case SkPathVerb::kClose:
                haveSeenClose = true;
                break;
        }

    }

    if (!SkIsFinite(distance)) {
        return nullptr;
    }
    if (fSegments.empty()) {
        return nullptr;
    }

    if (haveSeenClose) {
        SkScalar prevD = distance;
        SkPoint firstPt = fPts[0];
        distance = this->compute_line_seg(fPts[ptIndex], firstPt, distance, ptIndex);
        if (distance > prevD) {
            *fPts.append() = firstPt;
        }
    }

    SkDEBUGCODE(this->validate();)

    return new SkContourMeasure(std::move(fSegments), std::move(fPts), distance, haveSeenClose);
}

static void compute_pos_tan(const SkPoint pts[], unsigned segType,
                            SkScalar t, SkPoint* pos, SkVector* tangent) {
    switch (segType) {
        case kLine_SegType:
            if (pos) {
                pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
                         SkScalarInterp(pts[0].fY, pts[1].fY, t));
            }
            if (tangent) {
                tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
            }
            break;
        case kQuad_SegType:
            SkEvalQuadAt(pts, t, pos, tangent);
            if (tangent) {
                tangent->normalize();
            }
            break;
        case kConic_SegType: {
            SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent);
            if (tangent) {
                tangent->normalize();
            }
        } break;
        case kCubic_SegType:
            SkEvalCubicAt(pts, t, pos, tangent, nullptr);
            if (tangent) {
                tangent->normalize();
            }
            break;
        default:
            SkDEBUGFAIL("unknown segType");
    }
}


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

SkContourMeasureIter::SkContourMeasureIter() {
}

SkContourMeasureIter::SkContourMeasureIter(const SkPath& path, bool forceClosed,
                                           SkScalar resScale) {
    this->reset(path, forceClosed, resScale);
}

SkContourMeasureIter::~SkContourMeasureIter() {}

SkContourMeasureIter::SkContourMeasureIter(SkContourMeasureIter&&) = default;
SkContourMeasureIter& SkContourMeasureIter::operator=(SkContourMeasureIter&&) = default;

/** Assign a new path, or null to have none.
*/

void SkContourMeasureIter::reset(const SkPath& path, bool forceClosed, SkScalar resScale) {
    if (path.isFinite()) {
        fImpl = std::make_unique<Impl>(path, forceClosed, resScale);
    } else {
        fImpl.reset();
    }
}

sk_sp<SkContourMeasure> SkContourMeasureIter::next() {
    if (!fImpl) {
        return nullptr;
    }
    while (fImpl->hasNextSegments()) {
        auto cm = fImpl->buildSegments();
        if (cm) {
            return sk_sp<SkContourMeasure>(cm);
        }
    }
    return nullptr;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

SkContourMeasure::SkContourMeasure(SkTDArray<Segment>&& segs, SkTDArray<SkPoint>&& pts, SkScalar length, bool isClosed)
    : fSegments(std::move(segs))
    , fPts(std::move(pts))
    , fLength(length)
    , fIsClosed(isClosed)
    {}

template <typename T, typename K>
int SkTKSearch(const T base[], int count, const K& key) {
    SkASSERT(count >= 0);
    if (count <= 0) {
        return ~0;
    }

    SkASSERT(base != nullptr); // base may be nullptr if count is zero

    unsigned lo = 0;
    unsigned hi = count - 1;

    while (lo < hi) {
        unsigned mid = (hi + lo) >> 1;
        if (base[mid].fDistance < key) {
            lo = mid + 1;
        } else {
            hi = mid;
        }
    }

    if (base[hi].fDistance < key) {
        hi += 1;
        hi = ~hi;
    } else if (key < base[hi].fDistance) {
        hi = ~hi;
    }
    return hi;
}

const SkContourMeasure::Segment* SkContourMeasure::distanceToSegment( SkScalar distance,
                                                                     SkScalar* t) const {
    SkDEBUGCODE(SkScalar length = ) this->length();
    SkASSERT(distance >= 0 && distance <= length);

    const Segment*  seg = fSegments.begin();
    int             count = fSegments.size();

    int index = SkTKSearch<Segment, SkScalar>(seg, count, distance);
    // don't care if we hit an exact match or not, so we xor index if it is negative
    index ^= (index >> 31);
    seg = &seg[index];

    // now interpolate t-values with the prev segment (if possible)
    SkScalar    startT = 0, startD = 0;
    // check if the prev segment is legal, and references the same set of points
    if (index > 0) {
        startD = seg[-1].fDistance;
        if (seg[-1].fPtIndex == seg->fPtIndex) {
            SkASSERT(seg[-1].fType == seg->fType);
            startT = seg[-1].getScalarT();
        }
    }

    SkASSERT(seg->getScalarT() > startT);
    SkASSERT(distance >= startD);
    SkASSERT(seg->fDistance > startD);

    *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD);
    return seg;
}

bool SkContourMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) const {
    if (SkIsNaN(distance)) {
        return false;
    }

    const SkScalar length = this->length();
    SkASSERT(length > 0 && !fSegments.empty());

    // pin the distance to a legal range
    if (distance < 0) {
        distance = 0;
    } else if (distance > length) {
        distance = length;
    }

    SkScalar        t;
    const Segment*  seg = this->distanceToSegment(distance, &t);
    if (SkIsNaN(t)) {
        return false;
    }

    SkASSERT((unsigned)seg->fPtIndex < (unsigned)fPts.size());
    compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
    return true;
}

bool SkContourMeasure::getMatrix(SkScalar distance, SkMatrix* matrix, MatrixFlags flags) const {
    SkPoint     position;
    SkVector    tangent;

    if (this->getPosTan(distance, &position, &tangent)) {
        if (matrix) {
            if (flags & kGetTangent_MatrixFlag) {
                matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
            } else {
                matrix->reset();
            }
            if (flags & kGetPosition_MatrixFlag) {
                matrix->postTranslate(position.fX, position.fY);
            }
        }
        return true;
    }
    return false;
}

bool SkContourMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
                                  bool startWithMoveTo) const {
    SkASSERT(dst);

    SkScalar length = this->length();    // ensure we have built our segments

    if (startD < 0) {
        startD = 0;
    }
    if (stopD > length) {
        stopD = length;
    }
    if (!(startD <= stopD)) {   // catch NaN values as well
        return false;
    }
    if (fSegments.empty()) {
        return false;
    }

    SkPoint  p;
    SkScalar startT, stopT;
    const Segment* seg = this->distanceToSegment(startD, &startT);
    if (!SkIsFinite(startT)) {
        return false;
    }
    const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
    if (!SkIsFinite(stopT)) {
        return false;
    }
    SkASSERT(seg <= stopSeg);
    if (startWithMoveTo) {
        compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr);
        dst->moveTo(p);
    }

    if (seg->fPtIndex == stopSeg->fPtIndex) {
        SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
    } else {
        do {
            SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
            seg = SkContourMeasure::Segment::Next(seg);
            startT = 0;
        } while (seg->fPtIndex < stopSeg->fPtIndex);
        SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
    }

    return true;
}

SkContourMeasure::VerbMeasure SkContourMeasure::ForwardVerbIterator::operator*() const {
    static constexpr size_t seg_pt_count[] = {
        2, // kLine  (current_pt, 1 line pt)
        3, // kQuad  (current_pt, 2 quad pts)
        4, // kCubic (current_pt, 3 cubic pts)
        4, // kConic (current_pt, {weight, 0}, 2 conic pts)
    };
    static constexpr SkPathVerb seg_verb[] = {
        SkPathVerb::kLine,
        SkPathVerb::kQuad,
        SkPathVerb::kCubic,
        SkPathVerb::kConic,
    };
    static_assert(std::size(seg_pt_count) == std::size(seg_verb));
    static_assert(static_cast<size_t>(kLine_SegType)  < std::size(seg_pt_count));
    static_assert(static_cast<size_t>(kQuad_SegType)  < std::size(seg_pt_count));
    static_assert(static_cast<size_t>(kCubic_SegType) < std::size(seg_pt_count));
    static_assert(static_cast<size_t>(kConic_SegType) < std::size(seg_pt_count));

    SkASSERT(SkToSizeT(fSegments.front().fType) < std::size(seg_pt_count));
    SkASSERT(fSegments.front().fPtIndex + seg_pt_count[fSegments.front().fType] <= fPts.size());

    return {
        fSegments.front().fDistance,
        seg_verb[fSegments.front().fType],
        SkSpan(fPts.data() + fSegments.front().fPtIndex, seg_pt_count[fSegments.front().fType]),
    };
}

Messung V0.5
C=91 H=95 G=92

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.