quadratic.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import line from './line';
  2. import { distance, isNumberEqual, getBBoxByArray, piMod } from './util';
  3. import { nearestPoint } from './bezier';
  4. // 差值公式
  5. function quadraticAt(p0, p1, p2, t) {
  6. var onet = 1 - t;
  7. return onet * onet * p0 + 2 * t * onet * p1 + t * t * p2;
  8. }
  9. // 求极值
  10. function extrema(p0, p1, p2) {
  11. var a = p0 + p2 - 2 * p1;
  12. if (isNumberEqual(a, 0)) {
  13. return [0.5];
  14. }
  15. var rst = (p0 - p1) / a;
  16. if (rst <= 1 && rst >= 0) {
  17. return [rst];
  18. }
  19. return [];
  20. }
  21. function derivativeAt(p0, p1, p2, t) {
  22. return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1);
  23. }
  24. // 分割贝塞尔曲线
  25. function divideQuadratic(x1, y1, x2, y2, x3, y3, t) {
  26. // 划分点
  27. var xt = quadraticAt(x1, x2, x3, t);
  28. var yt = quadraticAt(y1, y2, y3, t);
  29. // 分割的第一条曲线的控制点
  30. var controlPoint1 = line.pointAt(x1, y1, x2, y2, t);
  31. // 分割的第二条曲线的控制点
  32. var controlPoint2 = line.pointAt(x2, y2, x3, y3, t);
  33. return [
  34. [x1, y1, controlPoint1.x, controlPoint1.y, xt, yt],
  35. [xt, yt, controlPoint2.x, controlPoint2.y, x3, y3],
  36. ];
  37. }
  38. // 使用迭代法取贝塞尔曲线的长度
  39. function quadraticLength(x1, y1, x2, y2, x3, y3, iterationCount) {
  40. if (iterationCount === 0) {
  41. return (distance(x1, y1, x2, y2) + distance(x2, y2, x3, y3) + distance(x1, y1, x3, y3)) / 2;
  42. }
  43. var quadratics = divideQuadratic(x1, y1, x2, y2, x3, y3, 0.5);
  44. var left = quadratics[0];
  45. var right = quadratics[1];
  46. left.push(iterationCount - 1);
  47. right.push(iterationCount - 1);
  48. return quadraticLength.apply(null, left) + quadraticLength.apply(null, right);
  49. }
  50. export default {
  51. box: function (x1, y1, x2, y2, x3, y3) {
  52. var xExtrema = extrema(x1, x2, x3)[0];
  53. var yExtrema = extrema(y1, y2, y3)[0];
  54. // 控制点不加入 box 的计算
  55. var xArr = [x1, x3];
  56. var yArr = [y1, y3];
  57. if (xExtrema !== undefined) {
  58. xArr.push(quadraticAt(x1, x2, x3, xExtrema));
  59. }
  60. if (yExtrema !== undefined) {
  61. yArr.push(quadraticAt(y1, y2, y3, yExtrema));
  62. }
  63. return getBBoxByArray(xArr, yArr);
  64. },
  65. length: function (x1, y1, x2, y2, x3, y3) {
  66. return quadraticLength(x1, y1, x2, y2, x3, y3, 3);
  67. },
  68. nearestPoint: function (x1, y1, x2, y2, x3, y3, x0, y0) {
  69. return nearestPoint([x1, x2, x3], [y1, y2, y3], x0, y0, quadraticAt);
  70. },
  71. pointDistance: function (x1, y1, x2, y2, x3, y3, x0, y0) {
  72. var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0);
  73. return distance(point.x, point.y, x0, y0);
  74. },
  75. interpolationAt: quadraticAt,
  76. pointAt: function (x1, y1, x2, y2, x3, y3, t) {
  77. return {
  78. x: quadraticAt(x1, x2, x3, t),
  79. y: quadraticAt(y1, y2, y3, t),
  80. };
  81. },
  82. divide: function (x1, y1, x2, y2, x3, y3, t) {
  83. return divideQuadratic(x1, y1, x2, y2, x3, y3, t);
  84. },
  85. tangentAngle: function (x1, y1, x2, y2, x3, y3, t) {
  86. var dx = derivativeAt(x1, x2, x3, t);
  87. var dy = derivativeAt(y1, y2, y3, t);
  88. var angle = Math.atan2(dy, dx);
  89. return piMod(angle);
  90. },
  91. };
  92. //# sourceMappingURL=quadratic.js.map