1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCubicMap.h" 9cb93a386Sopenharmony_ci#include "include/private/SkNx.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTPin.h" 11cb93a386Sopenharmony_ci#include "src/core/SkOpts.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci//#define CUBICMAP_TRACK_MAX_ERROR 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci#ifdef CUBICMAP_TRACK_MAX_ERROR 16cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h" 17cb93a386Sopenharmony_ci#endif 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cistatic inline bool nearly_zero(SkScalar x) { 20cb93a386Sopenharmony_ci SkASSERT(x >= 0); 21cb93a386Sopenharmony_ci return x <= 0.0000000001f; 22cb93a386Sopenharmony_ci} 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci#ifdef CUBICMAP_TRACK_MAX_ERROR 25cb93a386Sopenharmony_ci static int max_iters; 26cb93a386Sopenharmony_ci#endif 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci#ifdef CUBICMAP_TRACK_MAX_ERROR 29cb93a386Sopenharmony_cistatic float compute_slow(float A, float B, float C, float x) { 30cb93a386Sopenharmony_ci double roots[3]; 31cb93a386Sopenharmony_ci SkDEBUGCODE(int count =) SkDCubic::RootsValidT(A, B, C, -x, roots); 32cb93a386Sopenharmony_ci SkASSERT(count == 1); 33cb93a386Sopenharmony_ci return (float)roots[0]; 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cistatic float max_err; 37cb93a386Sopenharmony_ci#endif 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cistatic float compute_t_from_x(float A, float B, float C, float x) { 40cb93a386Sopenharmony_ci#ifdef CUBICMAP_TRACK_MAX_ERROR 41cb93a386Sopenharmony_ci float answer = compute_slow(A, B, C, x); 42cb93a386Sopenharmony_ci#endif 43cb93a386Sopenharmony_ci float answer2 = SkOpts::cubic_solver(A, B, C, -x); 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci#ifdef CUBICMAP_TRACK_MAX_ERROR 46cb93a386Sopenharmony_ci float err = sk_float_abs(answer - answer2); 47cb93a386Sopenharmony_ci if (err > max_err) { 48cb93a386Sopenharmony_ci max_err = err; 49cb93a386Sopenharmony_ci SkDebugf("max error %g\n", max_err); 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci#endif 52cb93a386Sopenharmony_ci return answer2; 53cb93a386Sopenharmony_ci} 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_cifloat SkCubicMap::computeYFromX(float x) const { 56cb93a386Sopenharmony_ci x = SkTPin(x, 0.0f, 1.0f); 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci if (nearly_zero(x) || nearly_zero(1 - x)) { 59cb93a386Sopenharmony_ci return x; 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci if (fType == kLine_Type) { 62cb93a386Sopenharmony_ci return x; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci float t; 65cb93a386Sopenharmony_ci if (fType == kCubeRoot_Type) { 66cb93a386Sopenharmony_ci t = sk_float_pow(x / fCoeff[0].fX, 1.0f / 3); 67cb93a386Sopenharmony_ci } else { 68cb93a386Sopenharmony_ci t = compute_t_from_x(fCoeff[0].fX, fCoeff[1].fX, fCoeff[2].fX, x); 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci float a = fCoeff[0].fY; 71cb93a386Sopenharmony_ci float b = fCoeff[1].fY; 72cb93a386Sopenharmony_ci float c = fCoeff[2].fY; 73cb93a386Sopenharmony_ci float y = ((a * t + b) * t + c) * t; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci return y; 76cb93a386Sopenharmony_ci} 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_cistatic inline bool coeff_nearly_zero(float delta) { 79cb93a386Sopenharmony_ci return sk_float_abs(delta) <= 0.0000001f; 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ciSkCubicMap::SkCubicMap(SkPoint p1, SkPoint p2) { 83cb93a386Sopenharmony_ci // Clamp X values only (we allow Ys outside [0..1]). 84cb93a386Sopenharmony_ci p1.fX = std::min(std::max(p1.fX, 0.0f), 1.0f); 85cb93a386Sopenharmony_ci p2.fX = std::min(std::max(p2.fX, 0.0f), 1.0f); 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci Sk2s s1 = Sk2s::Load(&p1) * 3; 88cb93a386Sopenharmony_ci Sk2s s2 = Sk2s::Load(&p2) * 3; 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci (Sk2s(1) + s1 - s2).store(&fCoeff[0]); 91cb93a386Sopenharmony_ci (s2 - s1 - s1).store(&fCoeff[1]); 92cb93a386Sopenharmony_ci s1.store(&fCoeff[2]); 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci fType = kSolver_Type; 95cb93a386Sopenharmony_ci if (SkScalarNearlyEqual(p1.fX, p1.fY) && SkScalarNearlyEqual(p2.fX, p2.fY)) { 96cb93a386Sopenharmony_ci fType = kLine_Type; 97cb93a386Sopenharmony_ci } else if (coeff_nearly_zero(fCoeff[1].fX) && coeff_nearly_zero(fCoeff[2].fX)) { 98cb93a386Sopenharmony_ci fType = kCubeRoot_Type; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci} 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ciSkPoint SkCubicMap::computeFromT(float t) const { 103cb93a386Sopenharmony_ci Sk2s a = Sk2s::Load(&fCoeff[0]); 104cb93a386Sopenharmony_ci Sk2s b = Sk2s::Load(&fCoeff[1]); 105cb93a386Sopenharmony_ci Sk2s c = Sk2s::Load(&fCoeff[2]); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci SkPoint result; 108cb93a386Sopenharmony_ci (((a * t + b) * t + c) * t).store(&result); 109cb93a386Sopenharmony_ci return result; 110cb93a386Sopenharmony_ci} 111