| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- "use strict";
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.bezierCurveToPolyline = bezierCurveToPolyline;
- exports.getBezierCurveLength = getBezierCurveLength;
- exports["default"] = void 0;
- var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
- var sqrt = Math.sqrt,
- pow = Math.pow,
- ceil = Math.ceil,
- abs = Math.abs; // Initialize the number of points per curve
- var defaultSegmentPointsNum = 50;
- /**
- * @example data structure of bezierCurve
- * bezierCurve = [
- * // Starting point of the curve
- * [10, 10],
- * // BezierCurve segment data (controlPoint1, controlPoint2, endPoint)
- * [
- * [20, 20], [40, 20], [50, 10]
- * ],
- * ...
- * ]
- */
- /**
- * @description Abstract the curve as a polyline consisting of N points
- * @param {Array} bezierCurve bezierCurve data
- * @param {Number} precision calculation accuracy. Recommended for 1-20. Default = 5
- * @return {Object} Calculation results and related data
- * @return {Array} Option.segmentPoints Point data that constitutes a polyline after calculation
- * @return {Number} Option.cycles Number of iterations
- * @return {Number} Option.rounds The number of recursions for the last iteration
- */
- function abstractBezierCurveToPolyline(bezierCurve) {
- var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
- var segmentsNum = bezierCurve.length - 1;
- var startPoint = bezierCurve[0];
- var endPoint = bezierCurve[segmentsNum][2];
- var segments = bezierCurve.slice(1);
- var getSegmentTPointFuns = segments.map(function (seg, i) {
- var beginPoint = i === 0 ? startPoint : segments[i - 1][2];
- return createGetBezierCurveTPointFun.apply(void 0, [beginPoint].concat((0, _toConsumableArray2["default"])(seg)));
- }); // Initialize the curve to a polyline
- var segmentPointsNum = new Array(segmentsNum).fill(defaultSegmentPointsNum);
- var segmentPoints = getSegmentPointsByNum(getSegmentTPointFuns, segmentPointsNum); // Calculate uniformly distributed points by iteratively
- var result = calcUniformPointsByIteration(segmentPoints, getSegmentTPointFuns, segments, precision);
- result.segmentPoints.push(endPoint);
- return result;
- }
- /**
- * @description Generate a method for obtaining corresponding point by t according to curve data
- * @param {Array} beginPoint BezierCurve begin point. [x, y]
- * @param {Array} controlPoint1 BezierCurve controlPoint1. [x, y]
- * @param {Array} controlPoint2 BezierCurve controlPoint2. [x, y]
- * @param {Array} endPoint BezierCurve end point. [x, y]
- * @return {Function} Expected function
- */
- function createGetBezierCurveTPointFun(beginPoint, controlPoint1, controlPoint2, endPoint) {
- return function (t) {
- var tSubed1 = 1 - t;
- var tSubed1Pow3 = pow(tSubed1, 3);
- var tSubed1Pow2 = pow(tSubed1, 2);
- var tPow3 = pow(t, 3);
- var tPow2 = pow(t, 2);
- return [beginPoint[0] * tSubed1Pow3 + 3 * controlPoint1[0] * t * tSubed1Pow2 + 3 * controlPoint2[0] * tPow2 * tSubed1 + endPoint[0] * tPow3, beginPoint[1] * tSubed1Pow3 + 3 * controlPoint1[1] * t * tSubed1Pow2 + 3 * controlPoint2[1] * tPow2 * tSubed1 + endPoint[1] * tPow3];
- };
- }
- /**
- * @description Get the distance between two points
- * @param {Array} point1 BezierCurve begin point. [x, y]
- * @param {Array} point2 BezierCurve controlPoint1. [x, y]
- * @return {Number} Expected distance
- */
- function getTwoPointDistance(_ref, _ref2) {
- var _ref3 = (0, _slicedToArray2["default"])(_ref, 2),
- ax = _ref3[0],
- ay = _ref3[1];
- var _ref4 = (0, _slicedToArray2["default"])(_ref2, 2),
- bx = _ref4[0],
- by = _ref4[1];
- return sqrt(pow(ax - bx, 2) + pow(ay - by, 2));
- }
- /**
- * @description Get the sum of the array of numbers
- * @param {Array} nums An array of numbers
- * @return {Number} Expected sum
- */
- function getNumsSum(nums) {
- return nums.reduce(function (sum, num) {
- return sum + num;
- }, 0);
- }
- /**
- * @description Get the distance of multiple sets of points
- * @param {Array} segmentPoints Multiple sets of point data
- * @return {Array} Distance of multiple sets of point data
- */
- function getSegmentPointsDistance(segmentPoints) {
- return segmentPoints.map(function (points, i) {
- return new Array(points.length - 1).fill(0).map(function (temp, j) {
- return getTwoPointDistance(points[j], points[j + 1]);
- });
- });
- }
- /**
- * @description Get the distance of multiple sets of points
- * @param {Array} segmentPoints Multiple sets of point data
- * @return {Array} Distance of multiple sets of point data
- */
- function getSegmentPointsByNum(getSegmentTPointFuns, segmentPointsNum) {
- return getSegmentTPointFuns.map(function (getSegmentTPointFun, i) {
- var tGap = 1 / segmentPointsNum[i];
- return new Array(segmentPointsNum[i]).fill('').map(function (foo, j) {
- return getSegmentTPointFun(j * tGap);
- });
- });
- }
- /**
- * @description Get the sum of deviations between line segment and the average length
- * @param {Array} segmentPointsDistance Segment length of polyline
- * @param {Number} avgLength Average length of the line segment
- * @return {Number} Deviations
- */
- function getAllDeviations(segmentPointsDistance, avgLength) {
- return segmentPointsDistance.map(function (seg) {
- return seg.map(function (s) {
- return abs(s - avgLength);
- });
- }).map(function (seg) {
- return getNumsSum(seg);
- }).reduce(function (total, v) {
- return total + v;
- }, 0);
- }
- /**
- * @description Calculate uniformly distributed points by iteratively
- * @param {Array} segmentPoints Multiple setd of points that make up a polyline
- * @param {Array} getSegmentTPointFuns Functions of get a point on the curve with t
- * @param {Array} segments BezierCurve data
- * @param {Number} precision Calculation accuracy
- * @return {Object} Calculation results and related data
- * @return {Array} Option.segmentPoints Point data that constitutes a polyline after calculation
- * @return {Number} Option.cycles Number of iterations
- * @return {Number} Option.rounds The number of recursions for the last iteration
- */
- function calcUniformPointsByIteration(segmentPoints, getSegmentTPointFuns, segments, precision) {
- // The number of loops for the current iteration
- var rounds = 4; // Number of iterations
- var cycles = 1;
- var _loop = function _loop() {
- // Recalculate the number of points per curve based on the last iteration data
- var totalPointsNum = segmentPoints.reduce(function (total, seg) {
- return total + seg.length;
- }, 0); // Add last points of segment to calc exact segment length
- segmentPoints.forEach(function (seg, i) {
- return seg.push(segments[i][2]);
- });
- var segmentPointsDistance = getSegmentPointsDistance(segmentPoints);
- var lineSegmentNum = segmentPointsDistance.reduce(function (total, seg) {
- return total + seg.length;
- }, 0);
- var segmentlength = segmentPointsDistance.map(function (seg) {
- return getNumsSum(seg);
- });
- var totalLength = getNumsSum(segmentlength);
- var avgLength = totalLength / lineSegmentNum; // Check if precision is reached
- var allDeviations = getAllDeviations(segmentPointsDistance, avgLength);
- if (allDeviations <= precision) return "break";
- totalPointsNum = ceil(avgLength / precision * totalPointsNum * 1.1);
- var segmentPointsNum = segmentlength.map(function (length) {
- return ceil(length / totalLength * totalPointsNum);
- }); // Calculate the points after redistribution
- segmentPoints = getSegmentPointsByNum(getSegmentTPointFuns, segmentPointsNum);
- totalPointsNum = segmentPoints.reduce(function (total, seg) {
- return total + seg.length;
- }, 0);
- var segmentPointsForLength = JSON.parse(JSON.stringify(segmentPoints));
- segmentPointsForLength.forEach(function (seg, i) {
- return seg.push(segments[i][2]);
- });
- segmentPointsDistance = getSegmentPointsDistance(segmentPointsForLength);
- lineSegmentNum = segmentPointsDistance.reduce(function (total, seg) {
- return total + seg.length;
- }, 0);
- segmentlength = segmentPointsDistance.map(function (seg) {
- return getNumsSum(seg);
- });
- totalLength = getNumsSum(segmentlength);
- avgLength = totalLength / lineSegmentNum;
- var stepSize = 1 / totalPointsNum / 10; // Recursively for each segment of the polyline
- getSegmentTPointFuns.forEach(function (getSegmentTPointFun, i) {
- var currentSegmentPointsNum = segmentPointsNum[i];
- var t = new Array(currentSegmentPointsNum).fill('').map(function (foo, j) {
- return j / segmentPointsNum[i];
- }); // Repeated recursive offset
- for (var r = 0; r < rounds; r++) {
- var distance = getSegmentPointsDistance([segmentPoints[i]])[0];
- var deviations = distance.map(function (d) {
- return d - avgLength;
- });
- var offset = 0;
- for (var j = 0; j < currentSegmentPointsNum; j++) {
- if (j === 0) return;
- offset += deviations[j - 1];
- t[j] -= stepSize * offset;
- if (t[j] > 1) t[j] = 1;
- if (t[j] < 0) t[j] = 0;
- segmentPoints[i][j] = getSegmentTPointFun(t[j]);
- }
- }
- });
- rounds *= 4;
- cycles++;
- };
- do {
- var _ret = _loop();
- if (_ret === "break") break;
- } while (rounds <= 1025);
- segmentPoints = segmentPoints.reduce(function (all, seg) {
- return all.concat(seg);
- }, []);
- return {
- segmentPoints: segmentPoints,
- cycles: cycles,
- rounds: rounds
- };
- }
- /**
- * @description Get the polyline corresponding to the Bezier curve
- * @param {Array} bezierCurve BezierCurve data
- * @param {Number} precision Calculation accuracy. Recommended for 1-20. Default = 5
- * @return {Array|Boolean} Point data that constitutes a polyline after calculation (Invalid input will return false)
- */
- function bezierCurveToPolyline(bezierCurve) {
- var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
- if (!bezierCurve) {
- console.error('bezierCurveToPolyline: Missing parameters!');
- return false;
- }
- if (!(bezierCurve instanceof Array)) {
- console.error('bezierCurveToPolyline: Parameter bezierCurve must be an array!');
- return false;
- }
- if (typeof precision !== 'number') {
- console.error('bezierCurveToPolyline: Parameter precision must be a number!');
- return false;
- }
- var _abstractBezierCurveT = abstractBezierCurveToPolyline(bezierCurve, precision),
- segmentPoints = _abstractBezierCurveT.segmentPoints;
- return segmentPoints;
- }
- /**
- * @description Get the bezier curve length
- * @param {Array} bezierCurve bezierCurve data
- * @param {Number} precision calculation accuracy. Recommended for 5-10. Default = 5
- * @return {Number|Boolean} BezierCurve length (Invalid input will return false)
- */
- function getBezierCurveLength(bezierCurve) {
- var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
- if (!bezierCurve) {
- console.error('getBezierCurveLength: Missing parameters!');
- return false;
- }
- if (!(bezierCurve instanceof Array)) {
- console.error('getBezierCurveLength: Parameter bezierCurve must be an array!');
- return false;
- }
- if (typeof precision !== 'number') {
- console.error('getBezierCurveLength: Parameter precision must be a number!');
- return false;
- }
- var _abstractBezierCurveT2 = abstractBezierCurveToPolyline(bezierCurve, precision),
- segmentPoints = _abstractBezierCurveT2.segmentPoints; // Calculate the total length of the points that make up the polyline
- var pointsDistance = getSegmentPointsDistance([segmentPoints])[0];
- var length = getNumsSum(pointsDistance);
- return length;
- }
- var _default = bezierCurveToPolyline;
- exports["default"] = _default;
|