// Two semi-common fast paths if (t == 0) { return {in_X(0), in_Y(0)};
} if (t == 1) { return {in_X(3), in_Y(3)};
} // X(t) = X_0*(1-t)^3 + 3*X_1*t(1-t)^2 + 3*X_2*t^2(1-t) + X_3*t^3 // Y(t) = Y_0*(1-t)^3 + 3*Y_1*t(1-t)^2 + 3*Y_2*t^2(1-t) + Y_3*t^3 // Some compilers are smart enough and have sufficient registers/intrinsics to write optimal // code from // double one_minus_t = 1 - t; // double a = one_minus_t * one_minus_t * one_minus_t; // double b = 3 * one_minus_t * one_minus_t * t; // double c = 3 * one_minus_t * t * t; // double d = t * t * t; // However, some (e.g. when compiling for ARM) fail to do so, so we use this form // to help more compilers generate smaller/faster ASM. https://godbolt.org/z/M6jG9x45c double one_minus_t = 1 - t; double one_minus_t_squared = one_minus_t * one_minus_t; double a = (one_minus_t_squared * one_minus_t); double b = 3 * one_minus_t_squared * t; double t_squared = t * t; double c = 3 * one_minus_t * t_squared; double d = t_squared * t;
return {a * in_X(0) + b * in_X(1) + c * in_X(2) + d * in_X(3),
a * in_Y(0) + b * in_Y(1) + c * in_Y(2) + d * in_Y(3)};
}
// Perform subdivision using De Casteljau's algorithm, that is, repeated linear // interpolation between adjacent points. void SkBezierCubic::Subdivide(constdouble curve[8], double t, double twoCurves[14]) {
SkASSERT(0.0 <= t && t <= 1.0); // We split the curve "in" into two curves "alpha" and "beta" constauto in_X = [&curve](size_t n) { return curve[2*n]; }; constauto in_Y = [&curve](size_t n) { return curve[2*n + 1]; }; constauto alpha_X = [&twoCurves](size_t n) -> double& { return twoCurves[2*n]; }; constauto alpha_Y = [&twoCurves](size_t n) -> double& { return twoCurves[2*n + 1]; }; constauto beta_X = [&twoCurves](size_t n) -> double& { return twoCurves[2*n + 6]; }; constauto beta_Y = [&twoCurves](size_t n) -> double& { return twoCurves[2*n + 7]; };
DPoint operator- (DPoint a) { return {-a.x, -a.y};
}
DPoint operator+ (DPoint a, DPoint b) { return {a.x + b.x, a.y + b.y};
}
DPoint operator- (DPoint a, DPoint b) { return {a.x - b.x, a.y - b.y};
}
DPoint operator* (double s, DPoint a) { return {s * a.x, s * a.y};
}
// Pin to 0 or 1 if within half a float ulp of 0 or 1. double pinTRange(double t) { // The ULPs around 0 are tiny compared to the ULPs around 1. Shift to 1 to use the same // size ULPs. if (sk_double_to_float(t + 1.0) == 1.0f) { return 0.0;
} elseif (sk_double_to_float(t) == 1.0f) { return 1.0;
} return t;
}
} // namespace
// Calculate A, B, C using doubles to reduce round-off error. const DPoint A = p0 - 2 * p1 + p2, // Remember we are generating the polynomial in the form A*t^2 -2*B*t + C, so the factor // of 2 is not needed and the term is negated. This term for a Bézier curve is usually // 2(p1-p0).
B = p0 - p1,
C = p0;
int intersectionCount = 0; // Round the roots to the nearest float to generate the values t. Valid t's are on the // domain [0, 1]. constdouble t0 = pinTRange(r0); if (0 <= t0 && t0 <= 1) {
intersectionStorage[intersectionCount++] = SkQuads::EvalAt(AX, -2 * BX, CX, t0);
}
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.