modeling/src/curves/bezier/lengths.js

  1. const valueAt = require('./valueAt')
  2. /**
  3. * Divides the bezier curve into line segments and returns the cumulative length of those segments as an array.
  4. * Utility function used to calculate the curve's approximate length and determine the equivalence between arc length and time.
  5. *
  6. * @example
  7. * const b = bezier.create([[0, 0], [0, 10]]);
  8. * const totalLength = lengths(100, b).pop(); // the last element of the array is the curve's approximate length
  9. *
  10. * @param {Number} segments the number of segments to use when approximating the curve length.
  11. * @param {Object} bezier a bezier curve.
  12. * @returns an array containing the cumulative length of the segments.
  13. */
  14. const lengths = (segments, bezier) => {
  15. let sum = 0
  16. const lengths = [0]
  17. let previous = valueAt(0, bezier)
  18. for (let index = 1; index <= segments; index++) {
  19. const current = valueAt(index / segments, bezier)
  20. sum += distanceBetween(current, previous)
  21. lengths.push(sum)
  22. previous = current
  23. }
  24. return lengths
  25. }
  26. /**
  27. * Calculates the Euclidean distance between two n-dimensional points.
  28. *
  29. * @example
  30. * const distance = distanceBetween([0, 0], [0, 10]); // calculate distance between 2D points
  31. * console.log(distance); // output 10
  32. *
  33. * @param {Array} a - first operand.
  34. * @param {Array} b - second operand.
  35. * @returns {Number} - distance.
  36. */
  37. const distanceBetween = (a, b) => {
  38. if (Number.isFinite(a) && Number.isFinite(b)) {
  39. return Math.abs(a - b)
  40. } else if (Array.isArray(a) && Array.isArray(b)) {
  41. if (a.length !== b.length) {
  42. throw new Error('The operands must have the same number of dimensions.')
  43. }
  44. let sum = 0
  45. for (let i = 0; i < a.length; i++) {
  46. sum += (b[i] - a[i]) * (b[i] - a[i])
  47. }
  48. return Math.sqrt(sum)
  49. } else {
  50. throw new Error('The operands must be of the same type, either number or array.')
  51. }
  52. }
  53. module.exports = lengths