SkCubicMap.cpp 2.7 KB

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