int SkDCubic::searchRoots(double extremeTs[6], int extrema, double axisIntercept, SearchAxis xAxis, double* validRoots) const { extrema += findInflections(&extremeTs[extrema]); extremeTs[extrema++] = 0; extremeTs[extrema] = 1; SkASSERT(extrema < 6); SkTQSort(extremeTs, extremeTs + extrema); int validCount = 0; for (int index = 0; index < extrema; ) { double min = extremeTs[index]; double max = extremeTs[++index]; if (min == max) { continue; } double newT = binarySearch(min, max, axisIntercept, xAxis); if (newT >= 0) { if (validCount >= 3) { return 0; } validRoots[validCount++] = newT; } } return validCount; }
// flavor that returns T values only, deferring computing the quads until they are needed // FIXME: when called from recursive intersect 2, this could take the original cubic // and do a more precise job when calling chop at and sub divide by computing the fractional ts. // it would still take the prechopped cubic for reduce order and find cubic inflections void SkDCubic::toQuadraticTs(double precision, SkTDArray<double>* ts) const { SkReduceOrder reducer; int order = reducer.reduce(*this, SkReduceOrder::kAllow_Quadratics, SkReduceOrder::kFill_Style); if (order < 3) { return; } double inflectT[5]; int inflections = findInflections(inflectT); SkASSERT(inflections <= 2); if (!endsAreExtremaInXOrY()) { inflections += findMaxCurvature(&inflectT[inflections]); SkASSERT(inflections <= 5); } QSort<double>(inflectT, &inflectT[inflections - 1]); // OPTIMIZATION: is this filtering common enough that it needs to be pulled out into its // own subroutine? while (inflections && approximately_less_than_zero(inflectT[0])) { memmove(inflectT, &inflectT[1], sizeof(inflectT[0]) * --inflections); } int start = 0; do { int next = start + 1; if (next >= inflections) { break; } if (!approximately_equal(inflectT[start], inflectT[next])) { ++start; continue; } memmove(&inflectT[start], &inflectT[next], sizeof(inflectT[0]) * (--inflections - start)); } while (true); while (inflections && approximately_greater_than_one(inflectT[inflections - 1])) { --inflections; } SkDCubicPair pair; if (inflections == 1) { pair = chopAt(inflectT[0]); int orderP1 = reducer.reduce(pair.first(), SkReduceOrder::kNo_Quadratics, SkReduceOrder::kFill_Style); if (orderP1 < 2) { --inflections; } else { int orderP2 = reducer.reduce(pair.second(), SkReduceOrder::kNo_Quadratics, SkReduceOrder::kFill_Style); if (orderP2 < 2) { --inflections; } } } if (inflections == 0 && add_simple_ts(*this, precision, ts)) { return; } if (inflections == 1) { pair = chopAt(inflectT[0]); addTs(pair.first(), precision, 0, inflectT[0], ts); addTs(pair.second(), precision, inflectT[0], 1, ts); return; } if (inflections > 1) { SkDCubic part = subDivide(0, inflectT[0]); addTs(part, precision, 0, inflectT[0], ts); int last = inflections - 1; for (int idx = 0; idx < last; ++idx) { part = subDivide(inflectT[idx], inflectT[idx + 1]); addTs(part, precision, inflectT[idx], inflectT[idx + 1], ts); } part = subDivide(inflectT[last], 1); addTs(part, precision, inflectT[last], 1, ts); return; } addTs(*this, precision, 0, 1, ts); }