UNPKG

@jscad/modeling

Version:

Constructive Solid Geometry (CSG) Library for JSCAD

64 lines (60 loc) 2.44 kB
const lengths = require('./lengths') /** * Convert a given arc length along a bezier curve to a t value. * Useful for generating equally spaced points along a bezier curve. * * @example * const points = []; * const segments = 9; // this will generate 10 equally spaced points * const increment = bezier.length(100, bezierCurve) / segments; * for(let i = 0; i <= segments; i++) { * const t = bezier.arcLengthToT({distance: i * increment}, bezierCurve); * const point = bezier.valueAt(t, bezierCurve); * points.push(point); * } * return points; * * @param {Object} [options] options for construction * @param {Number} [options.distance=0] the distance along the bezier curve for which we want to find the corresponding t value. * @param {Number} [options.segments=100] the number of segments to use when approximating the curve length. * @param {Object} bezier a bezier curve. * @returns a number in the [0, 1] interval or NaN if the arcLength is negative or greater than the total length of the curve. * @alias module:modeling/curves/bezier.arcLengthToT */ const arcLengthToT = (options, bezier) => { const defaults = { distance: 0, segments: 100 } const { distance, segments } = Object.assign({}, defaults, options) const arcLengths = lengths(segments, bezier) // binary search for the index with largest value smaller than target arcLength let startIndex = 0 let endIndex = segments while (startIndex <= endIndex) { const middleIndex = Math.floor(startIndex + (endIndex - startIndex) / 2) const diff = arcLengths[middleIndex] - distance if (diff < 0) { startIndex = middleIndex + 1 } else if (diff > 0) { endIndex = middleIndex - 1 } else { endIndex = middleIndex break } } // if we have an exact match, return it const targetIndex = endIndex if (arcLengths[targetIndex] === distance) { return targetIndex / segments } // we could get finer grain at lengths, or use simple interpolation between two points const lengthBefore = arcLengths[targetIndex] const lengthAfter = arcLengths[targetIndex + 1] const segmentLength = lengthAfter - lengthBefore // determine where we are between the 'before' and 'after' points const segmentFraction = (distance - lengthBefore) / segmentLength // add that fractional amount and return return (targetIndex + segmentFraction) / segments } module.exports = arcLengthToT