// from SkGeometry.cpp (and Numeric Solutions, 5.6) int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) { double s[3]; int realRoots = RootsReal(A, B, C, D, s); int foundRoots = SkDQuad::AddValidTs(s, realRoots, t); for (int index = 0; index < realRoots; ++index) { double tValue = s[index]; if (!approximately_one_or_less(tValue) && between(1, tValue, 1.00005)) { for (int idx2 = 0; idx2 < foundRoots; ++idx2) { if (approximately_equal(t[idx2], 1)) { goto nextRoot; } } SkASSERT(foundRoots < 3); t[foundRoots++] = 1; } else if (!approximately_zero_or_more(tValue) && between(-0.00005, tValue, 0)) { for (int idx2 = 0; idx2 < foundRoots; ++idx2) { if (approximately_equal(t[idx2], 0)) { goto nextRoot; } } SkASSERT(foundRoots < 3); t[foundRoots++] = 0; } nextRoot: ; } return foundRoots; }
// 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; }
bool lineIntersects(double lineT, const int x, int& roots) { if (!approximately_zero_or_more(lineT) || !approximately_one_or_less(lineT)) { if (x < --roots) { intersections.fT[0][x] = intersections.fT[0][roots]; } return false; } if (approximately_less_than_zero(lineT)) { lineT = 0; } else if (approximately_greater_than_one(lineT)) { lineT = 1; } intersections.fT[1][x] = lineT; return true; }
static void addValidRoots(const double roots[4], const int count, const int side, Intersections& i) { int index; for (index = 0; index < count; ++index) { if (!approximately_zero_or_more(roots[index]) || !approximately_one_or_less(roots[index])) { continue; } double t = 1 - roots[index]; if (approximately_less_than_zero(t)) { t = 0; } else if (approximately_greater_than_one(t)) { t = 1; } i.insertOne(t, side); } }
static int addValidRoots(const double roots[4], const int count, double valid[4]) { int result = 0; int index; for (index = 0; index < count; ++index) { if (!approximately_zero_or_more(roots[index]) || !approximately_one_or_less(roots[index])) { continue; } double t = 1 - roots[index]; if (approximately_less_than_zero(t)) { t = 0; } else if (approximately_greater_than_one(t)) { t = 1; } valid[result++] = t; } return result; }
/* Numeric Solutions (5.6) suggests to solve the quadratic by computing Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C)) and using the roots t1 = Q / A t2 = C / Q */ int add_valid_ts(double s[], int realRoots, double* t) { int foundRoots = 0; for (int index = 0; index < realRoots; ++index) { double tValue = s[index]; if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) { if (approximately_less_than_zero(tValue)) { tValue = 0; } else if (approximately_greater_than_one(tValue)) { tValue = 1; } for (int idx2 = 0; idx2 < foundRoots; ++idx2) { if (approximately_equal(t[idx2], tValue)) { goto nextRoot; } } t[foundRoots++] = tValue; } nextRoot: ; } return foundRoots; }