cubic.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var util_1 = require("./util");
  4. var line_1 = require("./line");
  5. var bezier_1 = require("./bezier");
  6. function cubicAt(p0, p1, p2, p3, t) {
  7. var onet = 1 - t; // t * t * t 的性能大概是 Math.pow(t, 3) 的三倍
  8. return onet * onet * onet * p0 + 3 * p1 * t * onet * onet + 3 * p2 * t * t * onet + p3 * t * t * t;
  9. }
  10. function derivativeAt(p0, p1, p2, p3, t) {
  11. var onet = 1 - t;
  12. return 3 * (onet * onet * (p1 - p0) + 2 * onet * t * (p2 - p1) + t * t * (p3 - p2));
  13. }
  14. function extrema(p0, p1, p2, p3) {
  15. var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3;
  16. var b = 6 * p0 - 12 * p1 + 6 * p2;
  17. var c = 3 * p1 - 3 * p0;
  18. var extremas = [];
  19. var t1;
  20. var t2;
  21. var discSqrt;
  22. if (util_1.isNumberEqual(a, 0)) {
  23. if (!util_1.isNumberEqual(b, 0)) {
  24. t1 = -c / b;
  25. if (t1 >= 0 && t1 <= 1) {
  26. extremas.push(t1);
  27. }
  28. }
  29. }
  30. else {
  31. var disc = b * b - 4 * a * c;
  32. if (util_1.isNumberEqual(disc, 0)) {
  33. extremas.push(-b / (2 * a));
  34. }
  35. else if (disc > 0) {
  36. discSqrt = Math.sqrt(disc);
  37. t1 = (-b + discSqrt) / (2 * a);
  38. t2 = (-b - discSqrt) / (2 * a);
  39. if (t1 >= 0 && t1 <= 1) {
  40. extremas.push(t1);
  41. }
  42. if (t2 >= 0 && t2 <= 1) {
  43. extremas.push(t2);
  44. }
  45. }
  46. }
  47. return extremas;
  48. }
  49. // 分割贝塞尔曲线
  50. function divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t) {
  51. // 划分点
  52. var xt = cubicAt(x1, x2, x3, x4, t);
  53. var yt = cubicAt(y1, y2, y3, y4, t);
  54. // 计算两点之间的差值点
  55. var c1 = line_1.default.pointAt(x1, y1, x2, y2, t);
  56. var c2 = line_1.default.pointAt(x2, y2, x3, y3, t);
  57. var c3 = line_1.default.pointAt(x3, y3, x4, y4, t);
  58. var c12 = line_1.default.pointAt(c1.x, c1.y, c2.x, c2.y, t);
  59. var c23 = line_1.default.pointAt(c2.x, c2.y, c3.x, c3.y, t);
  60. return [
  61. [x1, y1, c1.x, c1.y, c12.x, c12.y, xt, yt],
  62. [xt, yt, c23.x, c23.y, c3.x, c3.y, x4, y4],
  63. ];
  64. }
  65. // 使用迭代法取贝塞尔曲线的长度,二阶和三阶分开写,更清晰和便于调试
  66. function cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, iterationCount) {
  67. if (iterationCount === 0) {
  68. return bezier_1.snapLength([x1, x2, x3, x4], [y1, y2, y3, y4]);
  69. }
  70. var cubics = divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0.5);
  71. var left = cubics[0];
  72. var right = cubics[1];
  73. left.push(iterationCount - 1);
  74. right.push(iterationCount - 1);
  75. return cubicLength.apply(null, left) + cubicLength.apply(null, right);
  76. }
  77. exports.default = {
  78. extrema: extrema,
  79. box: function (x1, y1, x2, y2, x3, y3, x4, y4) {
  80. var xArr = [x1, x4];
  81. var yArr = [y1, y4];
  82. var xExtrema = extrema(x1, x2, x3, x4);
  83. var yExtrema = extrema(y1, y2, y3, y4);
  84. for (var i = 0; i < xExtrema.length; i++) {
  85. xArr.push(cubicAt(x1, x2, x3, x4, xExtrema[i]));
  86. }
  87. for (var i = 0; i < yExtrema.length; i++) {
  88. yArr.push(cubicAt(y1, y2, y3, y4, yExtrema[i]));
  89. }
  90. return util_1.getBBoxByArray(xArr, yArr);
  91. },
  92. length: function (x1, y1, x2, y2, x3, y3, x4, y4) {
  93. // 迭代三次,划分成 8 段求长度
  94. return cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, 3);
  95. },
  96. nearestPoint: function (x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) {
  97. return bezier_1.nearestPoint([x1, x2, x3, x4], [y1, y2, y3, y4], x0, y0, cubicAt, length);
  98. },
  99. pointDistance: function (x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) {
  100. var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length);
  101. return util_1.distance(point.x, point.y, x0, y0);
  102. },
  103. interpolationAt: cubicAt,
  104. pointAt: function (x1, y1, x2, y2, x3, y3, x4, y4, t) {
  105. return {
  106. x: cubicAt(x1, x2, x3, x4, t),
  107. y: cubicAt(y1, y2, y3, y4, t),
  108. };
  109. },
  110. divide: function (x1, y1, x2, y2, x3, y3, x4, y4, t) {
  111. return divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t);
  112. },
  113. tangentAngle: function (x1, y1, x2, y2, x3, y3, x4, y4, t) {
  114. var dx = derivativeAt(x1, x2, x3, x4, t);
  115. var dy = derivativeAt(y1, y2, y3, y4, t);
  116. return util_1.piMod(Math.atan2(dy, dx));
  117. },
  118. };
  119. //# sourceMappingURL=cubic.js.map