status_t Transaction::AddNodes(Node* node1, Node* node2, Node* node3) { ASSERT(fID >= 0); // sort the nodes swap_if_greater(node1, node2); if (node3 != NULL && swap_if_greater(node2, node3)) swap_if_greater(node1, node2); // add them status_t error = AddNode(node1); if (error == B_OK) error = AddNode(node2); if (error == B_OK && node3 != NULL) AddNode(node3); return error; }
void sort(T& a, T& b, T& c) { swap_if_greater(a, b); swap_if_greater(a, c); swap_if_greater(b, c); }
// Finds where to chop a non-loop around its intersection point. The resulting cubic segments will // be chopped such that a box of radius 'padRadius', centered at any point along the curve segment, // is guaranteed to not cross the tangent lines at the intersection point (a.k.a lines L & M). // // 'chops' will be filled with 0, 2, or 4 T values. The segments between T0..T1 and T2..T3 must be // drawn with quadratic splines instead of cubics. // // A loop intersection falls at two different T values, so this method takes Sk2f and computes the // padding for both in SIMD. static inline void find_chops_around_loop_intersection(float padRadius, Sk2f t2, Sk2f s2, const Sk2f& C0, const Sk2f& C1, ExcludedTerm skipTerm, float Cdet, SkSTArray<4, float>* chops) { SkASSERT(chops->empty()); SkASSERT(padRadius >= 0); padRadius /= std::abs(Cdet); // Scale this single value rather than all of C^-1 later on. // The parametric functions for distance from lines L & M are: // // l(T) = (T - Td)^2 * (T - Te) // m(T) = (T - Td) * (T - Te)^2 // // See "Resolution Independent Curve Rendering using Programmable Graphics Hardware", // 4.3 Finding klmn: // // https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf Sk2f T2 = t2/s2; // T2 is the double root of l(T). Sk2f T1 = SkNx_shuffle<1,0>(T2); // T1 is the other root of l(T). // Convert l(T), m(T) to power-basis form: // // | 1 1 | // |l(T) m(T)| = |T^3 T^2 T 1| * | l2 m2 | // | l1 m1 | // | l0 m0 | // // From here on we use Sk2f with "L" names, but the second lane will be for line M. Sk2f l2 = SkNx_fma(Sk2f(-2), T2, -T1); Sk2f l1 = T2 * SkNx_fma(Sk2f(2), T1, T2); Sk2f l0 = -T2*T2*T1; // The equation for line L can be found as follows: // // L = C^-1 * (l excluding skipTerm) // // (See comments for GrPathUtils::calcCubicInverseTransposePowerBasisMatrix.) // We are only interested in the normal to L, so only need the upper 2x2 of C^-1. And rather // than divide by determinant(C) here, we have already performed this divide on padRadius. Sk2f l2or1 = (ExcludedTerm::kLinearTerm == skipTerm) ? l2 : l1; Sk2f Lx = -C0[1]*l2or1 + C1[1]; // l3 is always 1. Sk2f Ly = C0[0]*l2or1 - C1[0]; // A box of radius "padRadius" is touching line L if "center dot L" is less than the Manhattan // with of L. (See rationale in are_collinear.) Sk2f Lwidth = Lx.abs() + Ly.abs(); Sk2f pad = Lwidth * padRadius; // Is l(T=0) outside the padding around line L? Sk2f lT0 = l0; // l(T=0) = |0 0 0 1| dot |1 l2 l1 l0| = l0 Sk2f outsideT0 = lT0.abs() - pad; // Is l(T=1) outside the padding around line L? Sk2f lT1 = (Sk2f(1) + l2 + l1 + l0).abs(); // l(T=1) = |1 1 1 1| dot |1 l2 l1 l0| Sk2f outsideT1 = lT1.abs() - pad; // Values for solving the cubic. Sk2f p, q, qqq, discr, numRoots, D; bool hasDiscr = false; // Values for calculating one root (rarely needed). Sk2f R, QQ; bool hasOneRootVals = false; // Values for calculating three roots. Sk2f P, cosTheta3; bool hasThreeRootVals = false; // Solve for the T values where l(T) = +pad and m(T) = -pad. for (int i = 0; i < 2; ++i) { float T = T2[i]; // T is the point we are chopping around. if ((T < 0 && outsideT0[i] >= 0) || (T > 1 && outsideT1[i] >= 0)) { // The padding around T is completely out of range. No point solving for it. continue; } if (!hasDiscr) { p = Sk2f(+.5f, -.5f) * pad; q = (1.f/3) * (T2 - T1); qqq = q*q*q; discr = qqq*p*2 + p*p; numRoots = (discr < 0).thenElse(3, 1); D = T2 - q; hasDiscr = true; } if (1 == numRoots[i]) { if (!hasOneRootVals) { Sk2f r = qqq + p; Sk2f s = r.abs() + discr.sqrt(); R = (r > 0).thenElse(-s, s); QQ = q*q; hasOneRootVals = true; } float A = cbrtf(R[i]); float B = A != 0 ? QQ[i]/A : 0; // When there is only one root, ine L chops from root..1, line M chops from 0..root. if (1 == i) { chops->push_back(0); } chops->push_back(A + B + D[i]); if (0 == i) { chops->push_back(1); } continue; } if (!hasThreeRootVals) { P = q.abs() * -2; cosTheta3 = (q >= 0).thenElse(1, -1) + p / qqq.abs(); hasThreeRootVals = true; } static constexpr float k2PiOver3 = 2 * SK_ScalarPI / 3; float theta = std::acos(cosTheta3[i]) * (1.f/3); float roots[3] = {P[i] * std::cos(theta) + D[i], P[i] * std::cos(theta + k2PiOver3) + D[i], P[i] * std::cos(theta - k2PiOver3) + D[i]}; // Sort the three roots. swap_if_greater(roots[0], roots[1]); swap_if_greater(roots[1], roots[2]); swap_if_greater(roots[0], roots[1]); // Line L chops around the first 2 roots, line M chops around the second 2. chops->push_back_n(2, &roots[i]); } }