bezier.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import { distance } from './util';
  2. var EPSILON = 0.0001;
  3. /**
  4. * 使用牛顿切割法求最近的点
  5. * @param {number[]} xArr 点的 x 数组
  6. * @param {number[]} yArr 点的 y 数组
  7. * @param {number} x 指定的点 x
  8. * @param {number} y 指定的点 y
  9. * @param {Function} tCallback 差值函数
  10. */
  11. export function nearestPoint(xArr, yArr, x, y, tCallback, length) {
  12. var t;
  13. var d = Infinity;
  14. var v0 = [x, y];
  15. var segNum = 20;
  16. if (length && length > 200) {
  17. segNum = length / 10;
  18. }
  19. var increaseRate = 1 / segNum;
  20. var interval = increaseRate / 10;
  21. for (var i = 0; i <= segNum; i++) {
  22. var _t = i * increaseRate;
  23. var v1 = [tCallback.apply(null, xArr.concat([_t])), tCallback.apply(null, yArr.concat([_t]))];
  24. var d1 = distance(v0[0], v0[1], v1[0], v1[1]);
  25. if (d1 < d) {
  26. t = _t;
  27. d = d1;
  28. }
  29. }
  30. // 提前终止
  31. if (t === 0) {
  32. return {
  33. x: xArr[0],
  34. y: yArr[0],
  35. };
  36. }
  37. if (t === 1) {
  38. var count = xArr.length;
  39. return {
  40. x: xArr[count - 1],
  41. y: yArr[count - 1],
  42. };
  43. }
  44. d = Infinity;
  45. for (var i = 0; i < 32; i++) {
  46. if (interval < EPSILON) {
  47. break;
  48. }
  49. var prev = t - interval;
  50. var next = t + interval;
  51. var v1 = [tCallback.apply(null, xArr.concat([prev])), tCallback.apply(null, yArr.concat([prev]))];
  52. var d1 = distance(v0[0], v0[1], v1[0], v1[1]);
  53. if (prev >= 0 && d1 < d) {
  54. t = prev;
  55. d = d1;
  56. }
  57. else {
  58. var v2 = [tCallback.apply(null, xArr.concat([next])), tCallback.apply(null, yArr.concat([next]))];
  59. var d2 = distance(v0[0], v0[1], v2[0], v2[1]);
  60. if (next <= 1 && d2 < d) {
  61. t = next;
  62. d = d2;
  63. }
  64. else {
  65. interval *= 0.5;
  66. }
  67. }
  68. }
  69. return {
  70. x: tCallback.apply(null, xArr.concat([t])),
  71. y: tCallback.apply(null, yArr.concat([t])),
  72. };
  73. }
  74. // 近似求解 https://community.khronos.org/t/3d-cubic-bezier-segment-length/62363/2
  75. export function snapLength(xArr, yArr) {
  76. var totalLength = 0;
  77. var count = xArr.length;
  78. for (var i = 0; i < count; i++) {
  79. var x = xArr[i];
  80. var y = yArr[i];
  81. var nextX = xArr[(i + 1) % count];
  82. var nextY = yArr[(i + 1) % count];
  83. totalLength += distance(x, y, nextX, nextY);
  84. }
  85. return totalLength / 2;
  86. }
  87. //# sourceMappingURL=bezier.js.map