// Solves linear system to extract klm // P.K = k (similarly for l, m) // Where P is matrix of control points // K is coefficients for the line K // k is vector of values of K evaluated at the control points // Solving for K, thus K = P^(-1) . k static void calc_cubic_klm(const SkPoint p[4], const SkScalar controlK[4], const SkScalar controlL[4], const SkScalar controlM[4], SkScalar k[3], SkScalar l[3], SkScalar m[3]) { SkMatrix matrix; matrix.setAll(p[0].fX, p[0].fY, 1.f, p[1].fX, p[1].fY, 1.f, p[2].fX, p[2].fY, 1.f); SkMatrix inverse; if (matrix.invert(&inverse)) { inverse.mapHomogeneousPoints(k, controlK, 1); inverse.mapHomogeneousPoints(l, controlL, 1); inverse.mapHomogeneousPoints(m, controlM, 1); } }
// Equations based off of Loop-Blinn Quadratic GPU Rendering // Input Parametric: // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) // Output Implicit: // f(x, y, w) = f(P) = K^2 - LM // K = dot(k, P), L = dot(l, P), M = dot(m, P) // k, l, m are calculated in function GrPathUtils::getConicKLM static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], const SkScalar weight) { SkMatrix klm; GrPathUtils::getConicKLM(p, weight, &klm); for (int i = 0; i < kQuadNumVertices; ++i) { const SkPoint3 pt3 = {verts[i].fPos.x(), verts[i].fPos.y(), 1.f}; klm.mapHomogeneousPoints((SkPoint3* ) verts[i].fConic.fKLM, &pt3, 1); } }
static void test_matrix_homogeneous(skiatest::Reporter* reporter) { SkMatrix mat; const float kRotation0 = 15.5f; const float kRotation1 = -50.f; const float kScale0 = 5000.f; const int kTripleCount = 1000; const int kMatrixCount = 1000; SkRandom rand; SkScalar randTriples[3*kTripleCount]; for (int i = 0; i < 3*kTripleCount; ++i) { randTriples[i] = rand.nextRangeF(-3000.f, 3000.f); } SkMatrix mats[kMatrixCount]; for (int i = 0; i < kMatrixCount; ++i) { for (int j = 0; j < 9; ++j) { mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f)); } } // identity { mat.reset(); SkScalar dst[3*kTripleCount]; mat.mapHomogeneousPoints(dst, randTriples, kTripleCount); REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(randTriples, dst, kTripleCount*3)); } // zero matrix { mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f); SkScalar dst[3*kTripleCount]; mat.mapHomogeneousPoints(dst, randTriples, kTripleCount); SkScalar zeros[3] = {0.f, 0.f, 0.f}; for (int i = 0; i < kTripleCount; ++i) { REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(&dst[i*3], zeros, 3)); } } // zero point { SkScalar zeros[3] = {0.f, 0.f, 0.f}; for (int i = 0; i < kMatrixCount; ++i) { SkScalar dst[3]; mats[i].mapHomogeneousPoints(dst, zeros, 1); REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(dst, zeros, 3)); } } // doesn't crash with null dst, src, count == 0 { mats[0].mapHomogeneousPoints(NULL, NULL, 0); } // uniform scale of point { mat.setScale(kScale0, kScale0); SkScalar dst[3]; SkScalar src[3] = {randTriples[0], randTriples[1], 1.f}; SkPoint pnt; pnt.set(src[0], src[1]); mat.mapHomogeneousPoints(dst, src, 1); mat.mapPoints(&pnt, &pnt, 1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1)); } // rotation of point { mat.setRotate(kRotation0); SkScalar dst[3]; SkScalar src[3] = {randTriples[0], randTriples[1], 1.f}; SkPoint pnt; pnt.set(src[0], src[1]); mat.mapHomogeneousPoints(dst, src, 1); mat.mapPoints(&pnt, &pnt, 1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1)); } // rotation, scale, rotation of point { mat.setRotate(kRotation1); mat.postScale(kScale0, kScale0); mat.postRotate(kRotation0); SkScalar dst[3]; SkScalar src[3] = {randTriples[0], randTriples[1], 1.f}; SkPoint pnt; pnt.set(src[0], src[1]); mat.mapHomogeneousPoints(dst, src, 1); mat.mapPoints(&pnt, &pnt, 1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1)); } // compare with naive approach { for (int i = 0; i < kMatrixCount; ++i) { for (int j = 0; j < kTripleCount; ++j) { SkScalar dst[3]; mats[i].mapHomogeneousPoints(dst, &randTriples[j*3], 1); REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], &randTriples[j*3], dst)); } } } }