static bool checkParallel(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2) {
    SkDVector sweep[2], tweep[2];
    setQuadHullSweep(quad1, sweep);
    setQuadHullSweep(quad2, tweep);
    // if the ctrl tangents are not nearly parallel, use them
    // solve for opposite direction displacement scale factor == m
    // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x
    // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1]
    // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x)
    //                       v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.x)
    // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x
    // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y)
    // m = v1.cross(v2) / v1.dot(v2)
    double s0dt0 = sweep[0].dot(tweep[0]);
    REPORTER_ASSERT(reporter, s0dt0 != 0);
    double s0xt0 = sweep[0].crossCheck(tweep[0]);
    double m = s0xt0 / s0dt0;
    double sDist = sweep[0].length() * m;
    double tDist = tweep[0].length() * m;
    bool useS = fabs(sDist) < fabs(tDist);
    double mFactor = fabs(useS ? distEndRatio(sDist, quad1) : distEndRatio(tDist, quad2));
    if (mFactor < 5000) {  // empirically found limit
        return s0xt0 < 0;
    }
    SkDVector m0 = quad1.ptAtT(0.5) - quad1[0];
    SkDVector m1 = quad2.ptAtT(0.5) - quad2[0];
    return m0.crossCheck(m1) < 0;
}
// returns false if there's more than one intercept or the intercept doesn't match the point
// returns true if the intercept was successfully added or if the
// original quads need to be subdivided
static bool add_intercept(const SkDQuad& q1, const SkDQuad& q2, double tMin, double tMax,
                          SkIntersections* i, bool* subDivide) {
    double tMid = (tMin + tMax) / 2;
    SkDPoint mid = q2.ptAtT(tMid);
    SkDLine line;
    line[0] = line[1] = mid;
    SkDVector dxdy = q2.dxdyAtT(tMid);
    line[0] -= dxdy;
    line[1] += dxdy;
    SkIntersections rootTs;
    rootTs.allowNear(false);
    int roots = rootTs.intersect(q1, line);
    if (roots == 0) {
        if (subDivide) {
            *subDivide = true;
        }
        return true;
    }
    if (roots == 2) {
        return false;
    }
    SkDPoint pt2 = q1.ptAtT(rootTs[0][0]);
    if (!pt2.approximatelyEqualHalf(mid)) {
        return false;
    }
    i->insertSwap(rootTs[0][0], tMid, pt2);
    return true;
}
static void testLineIntersect(skiatest::Reporter* reporter, const SkDQuad& quad,
                              const SkDLine& line, const double x, const double y) {
    char pathStr[1024];
    sk_bzero(pathStr, sizeof(pathStr));
    char* str = pathStr;
    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", quad[0].fX, quad[0].fY);
    str += sprintf(str, "    path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", quad[1].fX,
                   quad[1].fY, quad[2].fX, quad[2].fY);
    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", line[0].fX, line[0].fY);
    str += sprintf(str, "    path.lineTo(%1.9g, %1.9g);\n", line[1].fX, line[1].fY);

    SkIntersections intersections;
    bool flipped = false;
    int result = doIntersect(intersections, quad, line, flipped);
    bool found = false;
    for (int index = 0; index < result; ++index) {
        double quadT = intersections[0][index];
        SkDPoint quadXY = quad.ptAtT(quadT);
        double lineT = intersections[1][index];
        SkDPoint lineXY = line.ptAtT(lineT);
        if (quadXY.approximatelyEqual(lineXY)) {
            found = true;
        }
    }
    REPORTER_ASSERT(reporter, found);
}
/* returns
   -1 if overlaps
    0 if no overlap cw
    1 if no overlap ccw
*/
static int quadHullsOverlap(skiatest::Reporter* reporter, const SkDQuad& quad1,
        const SkDQuad& quad2) {
    SkDVector sweep[2], tweep[2];
    setQuadHullSweep(quad1, sweep);
    setQuadHullSweep(quad2, tweep);
    double s0xs1 = sweep[0].crossCheck(sweep[1]);
    double s0xt0 = sweep[0].crossCheck(tweep[0]);
    double s1xt0 = sweep[1].crossCheck(tweep[0]);
    bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0;
    double s0xt1 = sweep[0].crossCheck(tweep[1]);
    double s1xt1 = sweep[1].crossCheck(tweep[1]);
    tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0;
    double t0xt1 = tweep[0].crossCheck(tweep[1]);
    if (tBetweenS) {
        return -1;
    }
    if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) {  // s0 to s1 equals t0 to t1
        return -1;
    }
    bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0;
    sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0;
    if (sBetweenT) {
        return -1;
    }
    // if all of the sweeps are in the same half plane, then the order of any pair is enough
    if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) {
        return 0;
    }
    if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) {
        return 1;
    }
    // if the outside sweeps are greater than 180 degress:
        // first assume the inital tangents are the ordering
        // if the midpoint direction matches the inital order, that is enough
    SkDVector m0 = quad1.ptAtT(0.5) - quad1[0];
    SkDVector m1 = quad2.ptAtT(0.5) - quad2[0];
    double m0xm1 = m0.crossCheck(m1);
    if (s0xt0 > 0 && m0xm1 > 0) {
        return 0;
    }
    if (s0xt0 < 0 && m0xm1 < 0) {
        return 1;
    }
    REPORTER_ASSERT(reporter, s0xt0 != 0);
    return checkParallel(reporter, quad1, quad2);
}
Exemple #5
0
void SkGlyphCache::AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
                     SkGlyph::Intercept* intercept) {
    SkDQuad quad;
    quad.set(pts);
    double roots[2];
    int count = yAxis ? quad.verticalIntersect(axis, roots)
            : quad.horizontalIntersect(axis, roots);
    while (--count >= 0) {
        SkPoint pt = quad.ptAtT(roots[count]).asSkPoint();
        AddInterval(*(&pt.fX + yAxis), intercept);
    }
}
Exemple #6
0
void SkDRect::setBounds(const SkDQuad& quad) {
    set(quad[0]);
    add(quad[2]);
    double tValues[2];
    int roots = 0;
    if (!between(quad[0].fX, quad[1].fX, quad[2].fX)) {
        roots = SkDQuad::FindExtrema(quad[0].fX, quad[1].fX, quad[2].fX, tValues);
    }
    if (!between(quad[0].fY, quad[1].fY, quad[2].fY)) {
        roots += SkDQuad::FindExtrema(quad[0].fY, quad[1].fY, quad[2].fY, &tValues[roots]);
    }
    for (int x = 0; x < roots; ++x) {
        add(quad.ptAtT(tValues[x]));
    }
}
Exemple #7
0
DEF_TEST(PathOpsQuadLineIntersection, reporter) {
    for (size_t index = 0; index < lineQuadTests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const QuadPts& q = lineQuadTests[index].quad;
        SkDQuad quad;
        quad.debugSet(q.fPts);
        SkASSERT(ValidQuad(quad));
        const SkDLine& line = lineQuadTests[index].line;
        SkASSERT(ValidLine(line));
        SkReduceOrder reducer1, reducer2;
        int order1 = reducer1.reduce(quad);
        int order2 = reducer2.reduce(line);
        if (order1 < 3) {
            SkDebugf("%s [%d] quad order=%d\n", __FUNCTION__, iIndex, order1);
            REPORTER_ASSERT(reporter, 0);
        }
        if (order2 < 2) {
            SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, iIndex, order2);
            REPORTER_ASSERT(reporter, 0);
        }
        SkIntersections intersections;
        bool flipped = false;
        int result = doIntersect(intersections, quad, line, flipped);
        REPORTER_ASSERT(reporter, result == lineQuadTests[index].result);
        if (intersections.used() <= 0) {
            continue;
        }
        for (int pt = 0; pt < result; ++pt) {
            double tt1 = intersections[0][pt];
            REPORTER_ASSERT(reporter, tt1 >= 0 && tt1 <= 1);
            SkDPoint t1 = quad.ptAtT(tt1);
            double tt2 = intersections[1][pt];
            REPORTER_ASSERT(reporter, tt2 >= 0 && tt2 <= 1);
            SkDPoint t2 = line.ptAtT(tt2);
            if (!t1.approximatelyEqual(t2)) {
                SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
                    __FUNCTION__, iIndex, pt, tt1, t1.fX, t1.fY, tt2, t2.fX, t2.fY);
                REPORTER_ASSERT(reporter, 0);
            }
            if (!t1.approximatelyEqual(lineQuadTests[index].expected[0])
                    && (lineQuadTests[index].result == 1
                    || !t1.approximatelyEqual(lineQuadTests[index].expected[1]))) {
                SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.fX, t1.fY);
                REPORTER_ASSERT(reporter, 0);
            }
        }
    }
}
static void pointFinder(const SkDQuad& q1, const SkDQuad& q2) {
    for (int index = 0; index < 3; ++index) {
        double t = q1.nearestT(q2[index]);
        SkDPoint onQuad = q1.ptAtT(t);
        SkDebugf("%s t=%1.9g (%1.9g,%1.9g) dist=%1.9g\n", __FUNCTION__, t, onQuad.fX, onQuad.fY,
                onQuad.distance(q2[index]));
        double left[3];
        left[0] = ((const SkDLine&) q1[0]).isLeft(q2[index]);
        left[1] = ((const SkDLine&) q1[1]).isLeft(q2[index]);
        SkDLine diag = {{q1[0], q1[2]}};
        left[2] = diag.isLeft(q2[index]);
        SkDebugf("%s left=(%d, %d, %d) inHull=%s\n", __FUNCTION__, floatSign(left[0]),
                floatSign(left[1]), floatSign(left[2]),
                q1.pointInHull(q2[index]) ? "true" : "false");
    }
    SkDebugf("\n");
}
// find a point on a quad by choosing a t from 0 to 1
// create a vertical span above and below the point
// verify that intersecting the vertical span and the quad returns t
// verify that a vertical span starting at quad[0] intersects at t=0
// verify that a vertical span starting at quad[2] intersects at t=1
static void testQuadLineIntersectMain(PathOpsThreadState* data)
{
    PathOpsThreadState& state = *data;
    REPORTER_ASSERT(state.fReporter, data);
    int ax = state.fA & 0x03;
    int ay = state.fA >> 2;
    int bx = state.fB & 0x03;
    int by = state.fB >> 2;
    int cx = state.fC & 0x03;
    int cy = state.fC >> 2;
    SkDQuad quad = {{{(double) ax, (double) ay}, {(double) bx, (double) by},
            {(double) cx, (double) cy}
        }
    };
    SkReduceOrder reducer;
    int order = reducer.reduce(quad);
    if (order < 3) {
        return;
    }
    for (int tIndex = 0; tIndex <= 4; ++tIndex) {
        SkDPoint xy = quad.ptAtT(tIndex / 4.0);
        for (int h = -2; h <= 2; ++h) {
            for (int v = -2; v <= 2; ++v) {
                if (h == v && abs(h) != 1) {
                    continue;
                }
                double x = xy.fX;
                double y = xy.fY;
                SkDLine line = {{{x - h, y - v}, {x, y}}};
                testLineIntersect(state.fReporter, quad, line, x, y);
                state.fReporter->bumpTestCount();
                SkDLine line2 = {{{x, y}, {x + h, y + v}}};
                testLineIntersect(state.fReporter, quad, line2, x, y);
                state.fReporter->bumpTestCount();
                SkDLine line3 = {{{x - h, y - v}, {x + h, y + v}}};
                testLineIntersect(state.fReporter, quad, line3, x, y);
                state.fReporter->bumpTestCount();
            }
        }
    }
}
Exemple #10
0
static void testOneOffs(skiatest::Reporter* reporter) {
    bool flipped = false;
    for (size_t index = 0; index < oneOffs_count; ++index) {
        const QuadPts& q = oneOffs[index].quad;
        SkDQuad quad;
        quad.debugSet(q.fPts);
        SkASSERT(ValidQuad(quad));
        const SkDLine& line = oneOffs[index].line;
        SkASSERT(ValidLine(line));
        SkIntersections intersections;
        int result = doIntersect(intersections, quad, line, flipped);
        for (int inner = 0; inner < result; ++inner) {
            double quadT = intersections[0][inner];
            SkDPoint quadXY = quad.ptAtT(quadT);
            double lineT = intersections[1][inner];
            SkDPoint lineXY = line.ptAtT(lineT);
            if (!quadXY.approximatelyEqual(lineXY)) {
                quadXY.approximatelyEqual(lineXY);
                SkDebugf("");
            }
            REPORTER_ASSERT(reporter, quadXY.approximatelyEqual(lineXY));
        }
    }
}
Exemple #11
0
void DumpT(const SkDQuad& quad, double t) {
    SkDLine line = {{quad.ptAtT(t), quad[0]}};
    line.dump();
}
// each time through the loop, this computes values it had from the last loop
// if i == j == 1, the center values are still good
// otherwise, for i != 1 or j != 1, four of the values are still good
// and if i == 1 ^ j == 1, an additional value is good
static bool binary_search(const SkDQuad& quad1, const SkDQuad& quad2, double* t1Seed,
                          double* t2Seed, SkDPoint* pt) {
    double tStep = ROUGH_EPSILON;
    SkDPoint t1[3], t2[3];
    int calcMask = ~0;
    do {
        if (calcMask & (1 << 1)) t1[1] = quad1.ptAtT(*t1Seed);
        if (calcMask & (1 << 4)) t2[1] = quad2.ptAtT(*t2Seed);
        if (t1[1].approximatelyEqual(t2[1])) {
            *pt = t1[1];
    #if ONE_OFF_DEBUG
            SkDebugf("%s t1=%1.9g t2=%1.9g (%1.9g,%1.9g) == (%1.9g,%1.9g)\n", __FUNCTION__,
                    t1Seed, t2Seed, t1[1].fX, t1[1].fY, t1[2].fX, t1[2].fY);
    #endif
            return true;
        }
        if (calcMask & (1 << 0)) t1[0] = quad1.ptAtT(*t1Seed - tStep);
        if (calcMask & (1 << 2)) t1[2] = quad1.ptAtT(*t1Seed + tStep);
        if (calcMask & (1 << 3)) t2[0] = quad2.ptAtT(*t2Seed - tStep);
        if (calcMask & (1 << 5)) t2[2] = quad2.ptAtT(*t2Seed + tStep);
        double dist[3][3];
        // OPTIMIZE: using calcMask value permits skipping some distance calcuations
        //   if prior loop's results are moved to correct slot for reuse
        dist[1][1] = t1[1].distanceSquared(t2[1]);
        int best_i = 1, best_j = 1;
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                if (i == 1 && j == 1) {
                    continue;
                }
                dist[i][j] = t1[i].distanceSquared(t2[j]);
                if (dist[best_i][best_j] > dist[i][j]) {
                    best_i = i;
                    best_j = j;
                }
            }
        }
        if (best_i == 1 && best_j == 1) {
            tStep /= 2;
            if (tStep < FLT_EPSILON_HALF) {
                break;
            }
            calcMask = (1 << 0) | (1 << 2) | (1 << 3) | (1 << 5);
            continue;
        }
        if (best_i == 0) {
            *t1Seed -= tStep;
            t1[2] = t1[1];
            t1[1] = t1[0];
            calcMask = 1 << 0;
        } else if (best_i == 2) {
            *t1Seed += tStep;
            t1[0] = t1[1];
            t1[1] = t1[2];
            calcMask = 1 << 2;
        } else {
            calcMask = 0;
        }
        if (best_j == 0) {
            *t2Seed -= tStep;
            t2[2] = t2[1];
            t2[1] = t2[0];
            calcMask |= 1 << 3;
        } else if (best_j == 2) {
            *t2Seed += tStep;
            t2[0] = t2[1];
            t2[1] = t2[2];
            calcMask |= 1 << 5;
        }
    } while (true);
#if ONE_OFF_DEBUG
    SkDebugf("%s t1=%1.9g t2=%1.9g (%1.9g,%1.9g) != (%1.9g,%1.9g) %s\n", __FUNCTION__,
        t1Seed, t2Seed, t1[1].fX, t1[1].fY, t1[2].fX, t1[2].fY);
#endif
    return false;
}
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;
}
static bool bruteMinT(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
        TRange* lowerRange, TRange* upperRange) {
    double maxRadius = SkTMin(maxDist(quad1), maxDist(quad2));
    double maxQuads = SkTMax(maxQuad(quad1), maxQuad(quad2));
    double r = maxRadius / 2;
    double rStep = r / 2;
    SkDPoint best1 = {SK_ScalarInfinity, SK_ScalarInfinity};
    SkDPoint best2 = {SK_ScalarInfinity, SK_ScalarInfinity};
    int bestCCW = -1;
    double bestR = maxRadius;
    upperRange->tMin = 0;
    lowerRange->tMin = 1;
    do {
        do {  // find upper bounds of single result
            TRange tRange;
            bool stepUp = orderTRange(reporter, quad1, quad2, r, &tRange);
            if (stepUp) {
                SkDPoint pt1 = quad1.ptAtT(tRange.t1);
                if (equalPoints(pt1, best1, maxQuads)) {
                    break;
                }
                best1 = pt1;
                SkDPoint pt2 = quad2.ptAtT(tRange.t2);
                if (equalPoints(pt2, best2, maxQuads)) {
                    break;
                }
                best2 = pt2;
                if (gPathOpsAngleIdeasVerbose) {
                    SkDebugf("u bestCCW=%d ccw=%d bestMin=%1.9g:%1.9g r=%1.9g tMin=%1.9g\n",
                            bestCCW, tRange.ccw, lowerRange->tMin, upperRange->tMin, r,
                            tRange.tMin);
                }
                if (bestCCW >= 0 && bestCCW != (int) tRange.ccw) {
                    if (tRange.tMin < upperRange->tMin) {
                        upperRange->tMin = 0;
                    } else {
                        stepUp = false;
                    }
                }
                if (upperRange->tMin < tRange.tMin) {
                    bestCCW = tRange.ccw;
                    bestR = r;
                    *upperRange = tRange;
                }
                if (lowerRange->tMin > tRange.tMin) {
                    *lowerRange = tRange;
                }
            }
            r += stepUp ? rStep : -rStep;
            rStep /= 2;
        } while (rStep > FLT_EPSILON);
        if (bestCCW < 0) {
            REPORTER_ASSERT(reporter, bestR < maxRadius);
            return false;
        }
        double lastHighR = bestR;
        r = bestR / 2;
        rStep = r / 2;
        do {  // find lower bounds of single result
            TRange tRange;
            bool success = orderTRange(reporter, quad1, quad2, r, &tRange);
            if (success) {
                if (gPathOpsAngleIdeasVerbose) {
                    SkDebugf("l bestCCW=%d ccw=%d bestMin=%1.9g:%1.9g r=%1.9g tMin=%1.9g\n",
                            bestCCW, tRange.ccw, lowerRange->tMin, upperRange->tMin, r,
                            tRange.tMin);
                }
                if (bestCCW != (int) tRange.ccw || upperRange->tMin < tRange.tMin) {
                    bestCCW = tRange.ccw;
                    *upperRange = tRange;
                    bestR = lastHighR;
                    break;  // need to establish a new upper bounds
                }
                SkDPoint pt1 = quad1.ptAtT(tRange.t1);
                SkDPoint pt2 = quad2.ptAtT(tRange.t2);
                if (equalPoints(pt1, best1, maxQuads)) {
                    goto breakOut;
                }
                best1 = pt1;
                if (equalPoints(pt2, best2, maxQuads)) {
                    goto breakOut;
                }
                best2 = pt2;
                if (equalPoints(pt1, pt2, maxQuads)) {
                    success = false;
                } else {
                    if (upperRange->tMin < tRange.tMin) {
                        *upperRange = tRange;
                    }
                    if (lowerRange->tMin > tRange.tMin) {
                        *lowerRange = tRange;
                    }
                }
                lastHighR = SkTMin(r, lastHighR);
            }
            r += success ? -rStep : rStep;
            rStep /= 2;
        } while (rStep > FLT_EPSILON);
    } while (rStep > FLT_EPSILON);
breakOut:
    if (gPathOpsAngleIdeasVerbose) {
        SkDebugf("l a2-a1==%1.9g\n", lowerRange->a2 - lowerRange->a1);
    }
    return true;
}
static double quadAngle(skiatest::Reporter* reporter, const SkDQuad& quad, double t) {
    const SkDVector& pt = quad.ptAtT(t) - quad[0];
    double angle = (atan2(pt.fY, pt.fX) + SK_ScalarPI) * 8 / (SK_ScalarPI * 2);
    REPORTER_ASSERT(reporter, angle >= 0 && angle <= 8);
    return angle;
}
Exemple #16
0
static void setup(const SortSet* set, const size_t idx,
        SkOpSegment* seg, int* ts, const SkPoint& startPt) {
    SkPoint start, end;
    const SkPoint* data = set[idx].ptData;
    bool useIntersectPt = startPt.fX != 0 || startPt.fY != 0;
    if (useIntersectPt) {
        start = startPt;
        end = set[idx].endPt;
    }
    switch(set[idx].ptCount) {
        case 2: {
            SkASSERT(ValidPoints(data, 2));
            seg->addLine(data, false, false);
            SkDLine dLine;
            dLine.set(set[idx].ptData);
            SkASSERT(ValidLine(dLine));
            if (useIntersectPt) {
                break;
            }
            start = dLine.ptAtT(set[idx].tStart).asSkPoint();
            end = dLine.ptAtT(set[idx].tEnd).asSkPoint();
            } break;
        case 3: {
            SkASSERT(ValidPoints(data, 3));
            seg->addQuad(data, false, false);
            SkDQuad dQuad;
            dQuad.set(set[idx].ptData);
            SkASSERT(ValidQuad(dQuad));
             if (useIntersectPt) {
                break;
            }
            start = dQuad.ptAtT(set[idx].tStart).asSkPoint();
            end = dQuad.ptAtT(set[idx].tEnd).asSkPoint();
            } break;
        case 4: {
            SkASSERT(ValidPoints(data, 4));
            seg->addCubic(data, false, false);
            SkDCubic dCubic;
            dCubic.set(set[idx].ptData);
            SkASSERT(ValidCubic(dCubic));
            if (useIntersectPt) {
                break;
            }
            start = dCubic.ptAtT(set[idx].tStart).asSkPoint();
            end = dCubic.ptAtT(set[idx].tEnd).asSkPoint();
            } break;
    }
    double tStart = set[idx].tStart;
    double tEnd = set[idx].tEnd;
    seg->addT(NULL, start, tStart);
    seg->addT(NULL, end, tEnd);
    if (tStart != 0 && tEnd != 0) {
        seg->addT(NULL, set[idx].ptData[0], 0);
    }
    if (tStart != 1 && tEnd != 1) {
        seg->addT(NULL, set[idx].ptData[set[idx].ptCount - 1], 1);
    }
    int tIndex = 0;
    ts[0] = 0;
    ts[1] = 1;
    do {
        if (seg->t(tIndex) == set[idx].tStart) {
            ts[0] = tIndex;
        }
        if (seg->t(tIndex) == set[idx].tEnd) {
            ts[1] = tIndex;
        }
        if (seg->t(tIndex) >= 1) {
            break;
        }
    } while (++tIndex);
}