Пример #1
0
// first pass, add missing T values
// second pass, determine winding values of overlaps
void SkOpContour::addCoincidentPoints() {
    int count = fCoincidences.count();
    for (int index = 0; index < count; ++index) {
        SkCoincidence& coincidence = fCoincidences[index];
        int thisIndex = coincidence.fSegments[0];
        SkOpSegment& thisOne = fSegments[thisIndex];
        SkOpContour* otherContour = coincidence.fOther;
        int otherIndex = coincidence.fSegments[1];
        SkOpSegment& other = otherContour->fSegments[otherIndex];
        if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
            // OPTIMIZATION: remove from array
            continue;
        }
    #if DEBUG_CONCIDENT
        thisOne.debugShowTs();
        other.debugShowTs();
    #endif
        double startT = coincidence.fTs[0][0];
        double endT = coincidence.fTs[0][1];
        bool startSwapped, oStartSwapped, cancelers;
        if ((cancelers = startSwapped = startT > endT)) {
            SkTSwap(startT, endT);
        }
        SkASSERT(!approximately_negative(endT - startT));
        double oStartT = coincidence.fTs[1][0];
        double oEndT = coincidence.fTs[1][1];
        if ((oStartSwapped = oStartT > oEndT)) {
            SkTSwap(oStartT, oEndT);
            cancelers ^= true;
        }
        SkASSERT(!approximately_negative(oEndT - oStartT));
        if (cancelers) {
            // make sure startT and endT have t entries
            if (startT > 0 || oEndT < 1
                    || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
                thisOne.addTPair(startT, &other, oEndT, true, coincidence.fPts[startSwapped]);
            }
            if (oStartT > 0 || endT < 1
                    || thisOne.isMissing(endT) || other.isMissing(oStartT)) {
                other.addTPair(oStartT, &thisOne, endT, true, coincidence.fPts[oStartSwapped]);
            }
        } else {
            if (startT > 0 || oStartT > 0
                    || thisOne.isMissing(startT) || other.isMissing(oStartT)) {
                thisOne.addTPair(startT, &other, oStartT, true, coincidence.fPts[startSwapped]);
            }
            if (endT < 1 || oEndT < 1
                    || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
                other.addTPair(oEndT, &thisOne, endT, true, coincidence.fPts[!oStartSwapped]);
            }
        }
    #if DEBUG_CONCIDENT
        thisOne.debugShowTs();
        other.debugShowTs();
    #endif
    }
}
Пример #2
0
void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence) {
    if (coincidence.fNearly[0] && coincidence.fNearly[1]) {
        return;
    }
    int thisIndex = coincidence.fSegments[0];
    SkOpSegment& thisOne = fSegments[thisIndex];
    if (thisOne.done()) {
        return;
    }
    SkOpContour* otherContour = coincidence.fOther;
    int otherIndex = coincidence.fSegments[1];
    SkOpSegment& other = otherContour->fSegments[otherIndex];
    if (other.done()) {
        return;
    }
    double startT = coincidence.fTs[0][0];
    double endT = coincidence.fTs[0][1];
    const SkPoint* startPt = &coincidence.fPts[0][0];
    const SkPoint* endPt = &coincidence.fPts[0][1];
    bool cancelers;
    if ((cancelers = startT > endT)) {
        SkTSwap<double>(startT, endT);
        SkTSwap<const SkPoint*>(startPt, endPt);
    }
    if (startT == endT) { // if span is very large, the smaller may have collapsed to nothing
        if (endT <= 1 - FLT_EPSILON) {
            endT += FLT_EPSILON;
            SkASSERT(endT <= 1);
        } else {
            startT -= FLT_EPSILON;
            SkASSERT(startT >= 0);
        }
    }
    SkASSERT(!approximately_negative(endT - startT));
    double oStartT = coincidence.fTs[1][0];
    double oEndT = coincidence.fTs[1][1];
    if (oStartT > oEndT) {
        SkTSwap<double>(oStartT, oEndT);
        cancelers ^= true;
    }
    SkASSERT(!approximately_negative(oEndT - oStartT));
    if (cancelers) {
        thisOne.addTCancel(*startPt, *endPt, &other);
    } else {
        thisOne.addTCoincident(*startPt, *endPt, endT, &other);
    }
#if DEBUG_CONCIDENT
    thisOne.debugShowTs("p");
    other.debugShowTs("o");
#endif
}
Пример #3
0
void SkOpContour::resolveNearCoincidence() {
    int count = fCoincidences.count();
    for (int index = 0; index < count; ++index) {
        SkCoincidence& coincidence = fCoincidences[index];
        if (!coincidence.fNearly[0] || !coincidence.fNearly[1]) {
            continue;
        }
        int thisIndex = coincidence.fSegments[0];
        SkOpSegment& thisOne = fSegments[thisIndex];
        SkOpContour* otherContour = coincidence.fOther;
        int otherIndex = coincidence.fSegments[1];
        SkOpSegment& other = otherContour->fSegments[otherIndex];
        if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
            // OPTIMIZATION: remove from coincidence array
            continue;
        }
    #if DEBUG_CONCIDENT
        thisOne.debugShowTs("-");
        other.debugShowTs("o");
    #endif
        double startT = coincidence.fTs[0][0];
        double endT = coincidence.fTs[0][1];
        bool cancelers;
        if ((cancelers = startT > endT)) {
            SkTSwap<double>(startT, endT);
        }
        if (startT == endT) { // if span is very large, the smaller may have collapsed to nothing
            if (endT <= 1 - FLT_EPSILON) {
                endT += FLT_EPSILON;
                SkASSERT(endT <= 1);
            } else {
                startT -= FLT_EPSILON;
                SkASSERT(startT >= 0);
            }
        }
        SkASSERT(!approximately_negative(endT - startT));
        double oStartT = coincidence.fTs[1][0];
        double oEndT = coincidence.fTs[1][1];
        if (oStartT > oEndT) {
            SkTSwap<double>(oStartT, oEndT);
            cancelers ^= true;
        }
        SkASSERT(!approximately_negative(oEndT - oStartT));
        if (cancelers) {
            thisOne.blindCancel(coincidence, &other);
        } else {
            thisOne.blindCoincident(coincidence, &other);
        }
    }
}
Пример #4
0
// note: caller expects multiple results to be sorted smaller first
// note: http://en.wikipedia.org/wiki/Loss_of_significance has an interesting
//  analysis of the quadratic equation, suggesting why the following looks at
//  the sign of B -- and further suggesting that the greatest loss of precision
//  is in b squared less two a c
int quadraticRootsValidT(double A, double B, double C, double t[2]) {
#if 0
    B *= 2;
    double square = B * B - 4 * A * C;
    if (approximately_negative(square)) {
        if (!approximately_positive(square)) {
            return 0;
        }
        square = 0;
    }
    double squareRt = sqrt(square);
    double Q = (B + (B < 0 ? -squareRt : squareRt)) / -2;
    int foundRoots = 0;
    double ratio = Q / A;
    if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
        if (approximately_less_than_zero(ratio)) {
            ratio = 0;
        } else if (approximately_greater_than_one(ratio)) {
            ratio = 1;
        }
        t[0] = ratio;
        ++foundRoots;
    }
    ratio = C / Q;
    if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
        if (approximately_less_than_zero(ratio)) {
            ratio = 0;
        } else if (approximately_greater_than_one(ratio)) {
            ratio = 1;
        }
        if (foundRoots == 0 || !approximately_negative(ratio - t[0])) {
            t[foundRoots++] = ratio;
        } else if (!approximately_negative(t[0] - ratio)) {
            t[foundRoots++] = t[0];
            t[0] = ratio;
        }
    }
#else
    double s[2];
    int realRoots = quadraticRootsReal(A, B, C, s);
    int foundRoots = add_valid_ts(s, realRoots, t);
#endif
    return foundRoots;
}
Пример #5
0
void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence) {
    int thisIndex = coincidence.fSegments[0];
    SkOpSegment& thisOne = fSegments[thisIndex];
    if (thisOne.done()) {
        return;
    }
    SkOpContour* otherContour = coincidence.fOther;
    int otherIndex = coincidence.fSegments[1];
    SkOpSegment& other = otherContour->fSegments[otherIndex];
    if (other.done()) {
        return;
    }
    double startT = coincidence.fTs[0][0];
    double endT = coincidence.fTs[0][1];
    const SkPoint* startPt = &coincidence.fPts[0];
    const SkPoint* endPt = &coincidence.fPts[1];
    bool cancelers;
    if ((cancelers = startT > endT)) {
        SkTSwap<double>(startT, endT);
        SkTSwap<const SkPoint*>(startPt, endPt);
    }
    SkASSERT(!approximately_negative(endT - startT));
    double oStartT = coincidence.fTs[1][0];
    double oEndT = coincidence.fTs[1][1];
    if (oStartT > oEndT) {
        SkTSwap<double>(oStartT, oEndT);
        cancelers ^= true;
    }
    SkASSERT(!approximately_negative(oEndT - oStartT));
    if (cancelers) {
        thisOne.addTCancel(*startPt, *endPt, &other);
    } else {
        thisOne.addTCoincident(*startPt, *endPt, &other);
    }
#if DEBUG_CONCIDENT
    thisOne.debugShowTs();
    other.debugShowTs();
#endif
}
Пример #6
0
static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList,
                             SkOpSegment** current, int* index, int* endIndex, double* tHit,
                             SkScalar* hitDx, bool* tryAgain, bool opp) {
    double test = 0.9;
    int contourWinding;
    do {
        contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
                tryAgain, &test, opp);
        if (contourWinding != SK_MinS32 || *tryAgain) {
            return contourWinding;
        }
        test /= 2;
    } while (!approximately_negative(test));
    SkASSERT(0);  // should be OK to comment out, but interested when this hits
    return contourWinding;
}
Пример #7
0
static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList,
        SkOpSegment** currentPtr, int* indexPtr, int* endIndexPtr, double* tHit,
        SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) {
    double test = 0.9;
    int contourWinding;
    do {
        contourWinding = contourRangeCheckY(contourList, currentPtr, indexPtr, endIndexPtr,
                tHit, hitDx, tryAgain, &test, opp);
        if (contourWinding != SK_MinS32 || *tryAgain) {
            return contourWinding;
        }
        if (*currentPtr && (*currentPtr)->isVertical()) {
            *onlyVertical = true;
            return contourWinding;
        }
        test /= 2;
    } while (!approximately_negative(test));
    SkASSERT(0);  // FIXME: incomplete functionality
    return contourWinding;
}
static bool is_linear_inner(const SkDQuad& q1, double t1s, double t1e, const SkDQuad& q2,
                            double t2s, double t2e, SkIntersections* i, bool* subDivide) {
    SkDQuad hull = q1.subDivide(t1s, t1e);
    SkDLine line = {{hull[2], hull[0]}};
    const SkDLine* testLines[] = { &line, (const SkDLine*) &hull[0], (const SkDLine*) &hull[1] };
    const size_t kTestCount = SK_ARRAY_COUNT(testLines);
    SkSTArray<kTestCount * 2, double, true> tsFound;
    for (size_t index = 0; index < kTestCount; ++index) {
        SkIntersections rootTs;
        rootTs.allowNear(false);
        int roots = rootTs.intersect(q2, *testLines[index]);
        for (int idx2 = 0; idx2 < roots; ++idx2) {
            double t = rootTs[0][idx2];
#ifdef SK_DEBUG
            SkDPoint qPt = q2.ptAtT(t);
            SkDPoint lPt = testLines[index]->ptAtT(rootTs[1][idx2]);
            SkASSERT(qPt.approximatelyEqual(lPt));
#endif
            if (approximately_negative(t - t2s) || approximately_positive(t - t2e)) {
                continue;
            }
            tsFound.push_back(rootTs[0][idx2]);
        }
    }
    int tCount = tsFound.count();
    if (tCount <= 0) {
        return true;
    }
    double tMin, tMax;
    if (tCount == 1) {
        tMin = tMax = tsFound[0];
    } else {
        SkASSERT(tCount > 1);
        SkTQSort<double>(tsFound.begin(), tsFound.end() - 1);
        tMin = tsFound[0];
        tMax = tsFound[tsFound.count() - 1];
    }
    SkDPoint end = q2.ptAtT(t2s);
    bool startInTriangle = hull.pointInHull(end);
    if (startInTriangle) {
        tMin = t2s;
    }
    end = q2.ptAtT(t2e);
    bool endInTriangle = hull.pointInHull(end);
    if (endInTriangle) {
        tMax = t2e;
    }
    int split = 0;
    SkDVector dxy1, dxy2;
    if (tMin != tMax || tCount > 2) {
        dxy2 = q2.dxdyAtT(tMin);
        for (int index = 1; index < tCount; ++index) {
            dxy1 = dxy2;
            dxy2 = q2.dxdyAtT(tsFound[index]);
            double dot = dxy1.dot(dxy2);
            if (dot < 0) {
                split = index - 1;
                break;
            }
        }
    }
    if (split == 0) {  // there's one point
        if (add_intercept(q1, q2, tMin, tMax, i, subDivide)) {
            return true;
        }
        i->swap();
        return is_linear_inner(q2, tMin, tMax, q1, t1s, t1e, i, subDivide);
    }
    // At this point, we have two ranges of t values -- treat each separately at the split
    bool result;
    if (add_intercept(q1, q2, tMin, tsFound[split - 1], i, subDivide)) {
        result = true;
    } else {
        i->swap();
        result = is_linear_inner(q2, tMin, tsFound[split - 1], q1, t1s, t1e, i, subDivide);
    }
    if (add_intercept(q1, q2, tsFound[split], tMax, i, subDivide)) {
        result = true;
    } else {
        i->swap();
        result |= is_linear_inner(q2, tsFound[split], tMax, q1, t1s, t1e, i, subDivide);
    }
    return result;
}
Пример #9
0
// first pass, add missing T values
// second pass, determine winding values of overlaps
void SkOpContour::addCoincidentPoints() {
    int count = fCoincidences.count();
    for (int index = 0; index < count; ++index) {
        SkCoincidence& coincidence = fCoincidences[index];
        int thisIndex = coincidence.fSegments[0];
        SkOpSegment& thisOne = fSegments[thisIndex];
        SkOpContour* otherContour = coincidence.fOther;
        int otherIndex = coincidence.fSegments[1];
        SkOpSegment& other = otherContour->fSegments[otherIndex];
        if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
            // OPTIMIZATION: remove from array
            continue;
        }
    #if DEBUG_CONCIDENT
        thisOne.debugShowTs("-");
        other.debugShowTs("o");
    #endif
        double startT = coincidence.fTs[0][0];
        double endT = coincidence.fTs[0][1];
        bool startSwapped, oStartSwapped, cancelers;
        if ((cancelers = startSwapped = startT > endT)) {
            SkTSwap(startT, endT);
        }
        if (startT == endT) { // if one is very large the smaller may have collapsed to nothing
            if (endT <= 1 - FLT_EPSILON) {
                endT += FLT_EPSILON;
                SkASSERT(endT <= 1);
            } else {
                startT -= FLT_EPSILON;
                SkASSERT(startT >= 0);
            }
        }
        SkASSERT(!approximately_negative(endT - startT));
        double oStartT = coincidence.fTs[1][0];
        double oEndT = coincidence.fTs[1][1];
        if ((oStartSwapped = oStartT > oEndT)) {
            SkTSwap(oStartT, oEndT);
            cancelers ^= true;
        }
        SkASSERT(!approximately_negative(oEndT - oStartT));
        const SkPoint& startPt = coincidence.fPts[0][startSwapped];
        if (cancelers) {
            // make sure startT and endT have t entries
            if (startT > 0 || oEndT < 1
                    || thisOne.isMissing(startT, startPt) || other.isMissing(oEndT, startPt)) {
                thisOne.addTPair(startT, &other, oEndT, true, startPt,
                        coincidence.fPts[1][startSwapped]);
            }
            const SkPoint& oStartPt = coincidence.fPts[1][oStartSwapped];
            if (oStartT > 0 || endT < 1
                    || thisOne.isMissing(endT, oStartPt) || other.isMissing(oStartT, oStartPt)) {
                other.addTPair(oStartT, &thisOne, endT, true, oStartPt,
                        coincidence.fPts[0][oStartSwapped]);
            }
        } else {
            if (startT > 0 || oStartT > 0
                    || thisOne.isMissing(startT, startPt) || other.isMissing(oStartT, startPt)) {
                thisOne.addTPair(startT, &other, oStartT, true, startPt,
                        coincidence.fPts[1][startSwapped]);
            }
            const SkPoint& oEndPt = coincidence.fPts[1][!oStartSwapped];
            if (endT < 1 || oEndT < 1
                    || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT, oEndPt)) {
                other.addTPair(oEndT, &thisOne, endT, true, oEndPt,
                        coincidence.fPts[0][!oStartSwapped]);
            }
        }
    #if DEBUG_CONCIDENT
        thisOne.debugShowTs("+");
        other.debugShowTs("o");
    #endif
    }
    // if there are multiple pairs of coincidence that share an edge, see if the opposite
    // are also coincident
    for (int index = 0; index < count - 1; ++index) {
        const SkCoincidence& coincidence = fCoincidences[index];
        int thisIndex = coincidence.fSegments[0];
        SkOpContour* otherContour = coincidence.fOther;
        int otherIndex = coincidence.fSegments[1];
        for (int idx2 = 1; idx2 < count; ++idx2) {
            const SkCoincidence& innerCoin = fCoincidences[idx2];
            int innerThisIndex = innerCoin.fSegments[0];
            if (thisIndex == innerThisIndex) {
                checkCoincidentPair(coincidence, 1, innerCoin, 1, false);
            }
            if (this == otherContour && otherIndex == innerThisIndex) {
                checkCoincidentPair(coincidence, 0, innerCoin, 1, false);
            }
            SkOpContour* innerOtherContour = innerCoin.fOther;
            innerThisIndex = innerCoin.fSegments[1];
            if (this == innerOtherContour && thisIndex == innerThisIndex) {
                checkCoincidentPair(coincidence, 1, innerCoin, 0, false);
            }
            if (otherContour == innerOtherContour && otherIndex == innerThisIndex) {
                checkCoincidentPair(coincidence, 0, innerCoin, 0, false);
            }
        }
    }
}