@remotion/paths 4.0.164 → 4.0.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/debug-path.d.ts +6 -0
  2. package/dist/debug-path.js +57 -0
  3. package/dist/get-end-position.d.ts +2 -0
  4. package/dist/get-end-position.js +70 -0
  5. package/dist/helpers/types.d.ts +13 -12
  6. package/dist/index.d.ts +5 -1
  7. package/dist/index.js +3 -1
  8. package/dist/interpolate-path/convert-to-same-instruction-type.d.ts +22 -0
  9. package/dist/interpolate-path/convert-to-same-instruction-type.js +109 -0
  10. package/dist/interpolate-path/de-casteljau.d.ts +14 -0
  11. package/dist/interpolate-path/de-casteljau.js +44 -0
  12. package/dist/interpolate-path/extend-command.d.ts +2 -2
  13. package/dist/interpolate-path/extend-command.js +8 -7
  14. package/dist/interpolate-path/interpolate-commands.d.ts +16 -0
  15. package/dist/interpolate-path/interpolate-commands.js +108 -0
  16. package/dist/interpolate-path/interpolate-instruction-of-same-kind.d.ts +2 -0
  17. package/dist/interpolate-path/interpolate-instruction-of-same-kind.js +73 -0
  18. package/dist/interpolate-path/interpolate-instructions.d.ts +16 -0
  19. package/dist/interpolate-path/interpolate-instructions.js +92 -0
  20. package/dist/interpolate-path/interpolate-path.js +8 -116
  21. package/dist/interpolate-path/points-to-command.d.ts +9 -0
  22. package/dist/interpolate-path/points-to-command.js +46 -0
  23. package/dist/interpolate-path/split-curve-as-points.d.ts +8 -0
  24. package/dist/interpolate-path/split-curve-as-points.js +40 -0
  25. package/dist/interpolate-path/split-curve.d.ts +3 -3
  26. package/dist/interpolate-path/split-curve.js +18 -122
  27. package/dist/interpolate-path/split-segment.d.ts +2 -2
  28. package/dist/interpolate-path/split-segment.js +12 -12
  29. package/dist/warp-path/warp-helpers.d.ts +0 -3
  30. package/dist/warp-path/warp-helpers.js +1 -4
  31. package/package.json +1 -1
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.interpolateInstructionOfSameKind = void 0;
4
+ const interpolateLInstruction = (t, first, second) => {
5
+ return {
6
+ type: 'L',
7
+ x: (1 - t) * first.x + t * second.x,
8
+ y: (1 - t) * first.y + t * second.y,
9
+ };
10
+ };
11
+ const interpolateCInstructions = (t, first, second) => {
12
+ return {
13
+ type: 'C',
14
+ cp1x: (1 - t) * first.cp1x + t * second.cp1x,
15
+ cp2x: (1 - t) * first.cp2x + t * second.cp2x,
16
+ cp1y: (1 - t) * first.cp1y + t * second.cp1y,
17
+ cp2y: (1 - t) * first.cp2y + t * second.cp2y,
18
+ x: (1 - t) * first.x + t * second.x,
19
+ y: (1 - t) * first.y + t * second.y,
20
+ };
21
+ };
22
+ const interpolateQInstructions = (t, first, second) => {
23
+ return {
24
+ type: 'Q',
25
+ cpx: (1 - t) * first.cpx + t * second.cpx,
26
+ cpy: (1 - t) * first.cpy + t * second.cpy,
27
+ x: (1 - t) * first.x + t * second.x,
28
+ y: (1 - t) * first.y + t * second.y,
29
+ };
30
+ };
31
+ const interpolateMInstructions = (t, first, second) => {
32
+ return {
33
+ type: 'M',
34
+ x: (1 - t) * first.x + t * second.x,
35
+ y: (1 - t) * first.y + t * second.y,
36
+ };
37
+ };
38
+ const interpolateInstructionOfSameKind = (t, first, second) => {
39
+ if (first.type === 'L') {
40
+ if (second.type !== 'L') {
41
+ throw new Error('mismatch');
42
+ }
43
+ return interpolateLInstruction(t, first, second);
44
+ }
45
+ if (first.type === 'C') {
46
+ if (second.type !== 'C') {
47
+ throw new Error('mismatch');
48
+ }
49
+ return interpolateCInstructions(t, first, second);
50
+ }
51
+ if (first.type === 'Q') {
52
+ if (second.type !== 'Q') {
53
+ throw new Error('mismatch');
54
+ }
55
+ return interpolateQInstructions(t, first, second);
56
+ }
57
+ if (first.type === 'M') {
58
+ if (second.type !== 'M') {
59
+ throw new Error('mismatch');
60
+ }
61
+ return interpolateMInstructions(t, first, second);
62
+ }
63
+ if (first.type === 'Z') {
64
+ if (second.type !== 'Z') {
65
+ throw new Error('mismatch');
66
+ }
67
+ return {
68
+ type: 'Z',
69
+ };
70
+ }
71
+ throw new Error('mismatch');
72
+ };
73
+ exports.interpolateInstructionOfSameKind = interpolateInstructionOfSameKind;
@@ -0,0 +1,16 @@
1
+ import type { ReducedInstruction } from '../helpers/types';
2
+ /**
3
+ * Interpolate from A to B by extending A and B during interpolation to have
4
+ * the same number of points. This allows for a smooth transition when they
5
+ * have a different number of points.
6
+ *
7
+ * Ignores the `Z` command in paths unless both A and B end with it.
8
+ *
9
+ * This function works directly with arrays of command objects instead of with
10
+ * path `d` strings (see interpolatePath for working with `d` strings).
11
+ *
12
+ * @param {Object[]} aCommandsInput Array of path commands
13
+ * @param {Object[]} bCommandsInput Array of path commands
14
+ * @returns {Function} Interpolation function that maps t ([0, 1]) to an array of path commands.
15
+ */
16
+ export declare function interpolateInstructions(aCommandsInput: ReducedInstruction[], bCommandsInput: ReducedInstruction[]): (t: number) => ReducedInstruction[];
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.interpolateInstructions = void 0;
4
+ const get_end_position_1 = require("../get-end-position");
5
+ const convert_to_same_instruction_type_1 = require("./convert-to-same-instruction-type");
6
+ const extend_command_1 = require("./extend-command");
7
+ const interpolate_instruction_of_same_kind_1 = require("./interpolate-instruction-of-same-kind");
8
+ /**
9
+ * Interpolate from A to B by extending A and B during interpolation to have
10
+ * the same number of points. This allows for a smooth transition when they
11
+ * have a different number of points.
12
+ *
13
+ * Ignores the `Z` command in paths unless both A and B end with it.
14
+ *
15
+ * This function works directly with arrays of command objects instead of with
16
+ * path `d` strings (see interpolatePath for working with `d` strings).
17
+ *
18
+ * @param {Object[]} aCommandsInput Array of path commands
19
+ * @param {Object[]} bCommandsInput Array of path commands
20
+ * @returns {Function} Interpolation function that maps t ([0, 1]) to an array of path commands.
21
+ */
22
+ function interpolateInstructions(aCommandsInput, bCommandsInput) {
23
+ // make a copy so we don't mess with the input arrays
24
+ let aCommands = aCommandsInput.slice();
25
+ let bCommands = bCommandsInput.slice();
26
+ // both input sets are empty, so we don't interpolate
27
+ if (!aCommands.length && !bCommands.length) {
28
+ return function () {
29
+ return [];
30
+ };
31
+ }
32
+ // do we add Z during interpolation? yes if both have it. (we'd expect both to have it or not)
33
+ const addZ = (aCommands.length === 0 || aCommands[aCommands.length - 1].type === 'Z') &&
34
+ (bCommands.length === 0 || bCommands[bCommands.length - 1].type === 'Z');
35
+ // we temporarily remove Z
36
+ if (aCommands.length > 0 && aCommands[aCommands.length - 1].type === 'Z') {
37
+ aCommands.pop();
38
+ }
39
+ if (bCommands.length > 0 && bCommands[bCommands.length - 1].type === 'Z') {
40
+ bCommands.pop();
41
+ }
42
+ // if A is empty, treat it as if it used to contain just the first point
43
+ // of B. This makes it so the line extends out of from that first point.
44
+ if (!aCommands.length) {
45
+ aCommands.push(bCommands[0]);
46
+ // otherwise if B is empty, treat it as if it contains the first point
47
+ // of A. This makes it so the line retracts into the first point.
48
+ }
49
+ else if (!bCommands.length) {
50
+ bCommands.push(aCommands[0]);
51
+ }
52
+ // extend to match equal size
53
+ const numPointsToExtend = Math.abs(bCommands.length - aCommands.length);
54
+ if (numPointsToExtend !== 0) {
55
+ // B has more points than A, so add points to A before interpolating
56
+ if (bCommands.length > aCommands.length) {
57
+ aCommands = (0, extend_command_1.extendInstruction)(aCommands, bCommands);
58
+ // else if A has more points than B, add more points to B
59
+ }
60
+ else if (bCommands.length < aCommands.length) {
61
+ bCommands = (0, extend_command_1.extendInstruction)(bCommands, aCommands);
62
+ }
63
+ }
64
+ // commands have same length now.
65
+ // convert commands in A to the same type as those in B
66
+ const aSameType = aCommands.map((aCommand, i) => {
67
+ const commandsUntilNow = aCommands.slice(0, i);
68
+ const point = (0, get_end_position_1.getEndPosition)(commandsUntilNow);
69
+ return (0, convert_to_same_instruction_type_1.convertToSameInstructionType)(aCommand, bCommands[i], point);
70
+ });
71
+ const interpolatedCommands = [];
72
+ if (addZ) {
73
+ aSameType.push({ type: 'Z' }); // required for when returning at t == 0
74
+ bCommands.push({ type: 'Z' });
75
+ }
76
+ return function (t) {
77
+ // at 1 return the final value without the extensions used during interpolation
78
+ if (t === 1) {
79
+ return bCommandsInput;
80
+ }
81
+ // work with aCommands directly since interpolatedCommands are mutated
82
+ if (t === 0) {
83
+ return aSameType;
84
+ }
85
+ // interpolate the commands using the mutable interpolated command objs
86
+ for (let i = 0; i < aSameType.length; ++i) {
87
+ interpolatedCommands.push((0, interpolate_instruction_of_same_kind_1.interpolateInstructionOfSameKind)(t, aSameType[i], bCommands[i]));
88
+ }
89
+ return interpolatedCommands;
90
+ };
91
+ }
92
+ exports.interpolateInstructions = interpolateInstructions;
@@ -33,112 +33,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
33
  */
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
35
  exports.interpolatePath = void 0;
36
- const command_1 = require("./command");
37
- const command_to_string_1 = require("./command-to-string");
38
- const convert_to_same_type_1 = require("./convert-to-same-type");
39
- const extend_command_1 = require("./extend-command");
40
- const path_commands_from_string_1 = require("./path-commands-from-string");
41
- /**
42
- * Interpolate from A to B by extending A and B during interpolation to have
43
- * the same number of points. This allows for a smooth transition when they
44
- * have a different number of points.
45
- *
46
- * Ignores the `Z` command in paths unless both A and B end with it.
47
- *
48
- * This function works directly with arrays of command objects instead of with
49
- * path `d` strings (see interpolatePath for working with `d` strings).
50
- *
51
- * @param {Object[]} aCommandsInput Array of path commands
52
- * @param {Object[]} bCommandsInput Array of path commands
53
- * @returns {Function} Interpolation function that maps t ([0, 1]) to an array of path commands.
54
- */
55
- function interpolatePathCommands(aCommandsInput, bCommandsInput) {
56
- // make a copy so we don't mess with the input arrays
57
- let aCommands = aCommandsInput === null || aCommandsInput === undefined
58
- ? []
59
- : aCommandsInput.slice();
60
- let bCommands = bCommandsInput === null || bCommandsInput === undefined
61
- ? []
62
- : bCommandsInput.slice();
63
- // both input sets are empty, so we don't interpolate
64
- if (!aCommands.length && !bCommands.length) {
65
- return function () {
66
- return [];
67
- };
68
- }
69
- // do we add Z during interpolation? yes if both have it. (we'd expect both to have it or not)
70
- const addZ = (aCommands.length === 0 || aCommands[aCommands.length - 1].type === 'Z') &&
71
- (bCommands.length === 0 || bCommands[bCommands.length - 1].type === 'Z');
72
- // we temporarily remove Z
73
- if (aCommands.length > 0 && aCommands[aCommands.length - 1].type === 'Z') {
74
- aCommands.pop();
75
- }
76
- if (bCommands.length > 0 && bCommands[bCommands.length - 1].type === 'Z') {
77
- bCommands.pop();
78
- }
79
- // if A is empty, treat it as if it used to contain just the first point
80
- // of B. This makes it so the line extends out of from that first point.
81
- if (!aCommands.length) {
82
- aCommands.push(bCommands[0]);
83
- // otherwise if B is empty, treat it as if it contains the first point
84
- // of A. This makes it so the line retracts into the first point.
85
- }
86
- else if (!bCommands.length) {
87
- bCommands.push(aCommands[0]);
88
- }
89
- // extend to match equal size
90
- const numPointsToExtend = Math.abs(bCommands.length - aCommands.length);
91
- if (numPointsToExtend !== 0) {
92
- // B has more points than A, so add points to A before interpolating
93
- if (bCommands.length > aCommands.length) {
94
- aCommands = (0, extend_command_1.extend)(aCommands, bCommands);
95
- // else if A has more points than B, add more points to B
96
- }
97
- else if (bCommands.length < aCommands.length) {
98
- bCommands = (0, extend_command_1.extend)(bCommands, aCommands);
99
- }
100
- }
101
- // commands have same length now.
102
- // convert commands in A to the same type as those in B
103
- aCommands = aCommands.map((aCommand, i) => (0, convert_to_same_type_1.convertToSameType)(aCommand, bCommands[i]));
104
- // create mutable interpolated command objects
105
- const interpolatedCommands = aCommands.map((aCommand) => ({ ...aCommand }));
106
- if (addZ) {
107
- interpolatedCommands.push({ type: 'Z' });
108
- aCommands.push({ type: 'Z' }); // required for when returning at t == 0
109
- }
110
- return function (t) {
111
- // at 1 return the final value without the extensions used during interpolation
112
- if (t === 1) {
113
- return bCommandsInput === null || bCommandsInput === undefined
114
- ? []
115
- : bCommandsInput;
116
- }
117
- // work with aCommands directly since interpolatedCommands are mutated
118
- if (t === 0) {
119
- return aCommands;
120
- }
121
- // interpolate the commands using the mutable interpolated command objs
122
- for (let i = 0; i < interpolatedCommands.length; ++i) {
123
- // if (interpolatedCommands[i].type === 'Z') continue;
124
- const aCommand = aCommands[i];
125
- const bCommand = bCommands[i];
126
- const interpolatedCommand = interpolatedCommands[i];
127
- for (const arg of command_1.typeMap[interpolatedCommand.type]) {
128
- // @ts-expect-error
129
- interpolatedCommand[arg] =
130
- (1 - t) * aCommand[arg] +
131
- t * bCommand[arg];
132
- // do not use floats for flags (#27), round to integer
133
- if (arg === 'largeArcFlag' || arg === 'sweepFlag') {
134
- // @ts-expect-error
135
- interpolatedCommand[arg] = Math.round(interpolatedCommand[arg]);
136
- }
137
- }
138
- }
139
- return interpolatedCommands;
140
- };
141
- }
36
+ const parse_path_1 = require("../parse-path");
37
+ const reduce_instructions_1 = require("../reduce-instructions");
38
+ const serialize_instructions_1 = require("../serialize-instructions");
39
+ const interpolate_instructions_1 = require("./interpolate-instructions");
142
40
  /**
143
41
  * @description Interpolates between two SVG paths.
144
42
  * @param {number} value A number - 0 means first path, 1 means second path, any other values will be interpolated
@@ -154,21 +52,15 @@ const interpolatePath = (value, firstPath, secondPath) => {
154
52
  if (value === 0) {
155
53
  return firstPath;
156
54
  }
157
- const aCommands = (0, path_commands_from_string_1.pathCommandsFromString)(firstPath);
55
+ const aCommands = (0, reduce_instructions_1.reduceInstructions)((0, parse_path_1.parsePath)(firstPath));
158
56
  if (aCommands.length === 0) {
159
57
  throw new TypeError(`SVG Path "${firstPath}" is not valid`);
160
58
  }
161
- const bCommands = (0, path_commands_from_string_1.pathCommandsFromString)(secondPath);
59
+ const bCommands = (0, reduce_instructions_1.reduceInstructions)((0, parse_path_1.parsePath)(secondPath));
162
60
  if (bCommands.length === 0) {
163
61
  throw new TypeError(`SVG Path "${secondPath}" is not valid`);
164
62
  }
165
- const commandInterpolator = interpolatePathCommands(aCommands, bCommands);
166
- const interpolatedCommands = commandInterpolator(value);
167
- // convert to a string (fastest concat: https://jsperf.com/join-concat/150)
168
- return interpolatedCommands
169
- .map((c) => {
170
- return (0, command_to_string_1.commandToString)(c);
171
- })
172
- .join(' ');
63
+ const commandInterpolator = (0, interpolate_instructions_1.interpolateInstructions)(aCommands, bCommands);
64
+ return (0, serialize_instructions_1.serializeInstructions)(commandInterpolator(value));
173
65
  };
174
66
  exports.interpolatePath = interpolatePath;
@@ -0,0 +1,9 @@
1
+ import type { ReducedInstruction } from '../helpers/types';
2
+ /**
3
+ * Convert segments represented as points back into a command object
4
+ *
5
+ * @param {Number[][]} points Array of [x,y] points: [start, control1, control2, ..., end]
6
+ * Represents a segment
7
+ * @return {Object} A command object representing the segment.
8
+ */
9
+ export declare function pointsToInstruction(points: number[][]): ReducedInstruction;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pointsToInstruction = void 0;
4
+ /**
5
+ * Convert segments represented as points back into a command object
6
+ *
7
+ * @param {Number[][]} points Array of [x,y] points: [start, control1, control2, ..., end]
8
+ * Represents a segment
9
+ * @return {Object} A command object representing the segment.
10
+ */
11
+ function pointsToInstruction(points) {
12
+ const x = points[points.length - 1][0];
13
+ const y = points[points.length - 1][1];
14
+ if (points.length === 4) {
15
+ const x1 = points[1][0];
16
+ const y1 = points[1][1];
17
+ const x2 = points[2][0];
18
+ const y2 = points[2][1];
19
+ return {
20
+ type: 'C',
21
+ cp1x: x1,
22
+ cp1y: y1,
23
+ cp2x: x2,
24
+ cp2y: y2,
25
+ x,
26
+ y,
27
+ };
28
+ }
29
+ if (points.length === 3) {
30
+ const x1 = points[1][0];
31
+ const y1 = points[1][1];
32
+ return {
33
+ type: 'Q',
34
+ cpx: x1,
35
+ cpy: y1,
36
+ x,
37
+ y,
38
+ };
39
+ }
40
+ return {
41
+ type: 'L',
42
+ x,
43
+ y,
44
+ };
45
+ }
46
+ exports.pointsToInstruction = pointsToInstruction;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Runs de Casteljau's algorithm enough times to produce the desired number of segments.
3
+ *
4
+ * @param {Number[][]} points Array of [x,y] points for de Casteljau (the initial segment to split)
5
+ * @param {Number} segmentCount Number of segments to split the original into
6
+ * @return {Number[][][]} Array of segments
7
+ */
8
+ export declare function splitCurveAsPoints(points: number[][], segmentCount?: number): number[][][];
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.splitCurveAsPoints = void 0;
4
+ const de_casteljau_1 = require("./de-casteljau");
5
+ /**
6
+ * Runs de Casteljau's algorithm enough times to produce the desired number of segments.
7
+ *
8
+ * @param {Number[][]} points Array of [x,y] points for de Casteljau (the initial segment to split)
9
+ * @param {Number} segmentCount Number of segments to split the original into
10
+ * @return {Number[][][]} Array of segments
11
+ */
12
+ function splitCurveAsPoints(points, segmentCount = 2) {
13
+ const segments = [];
14
+ let remainingCurve = points;
15
+ const tIncrement = 1 / segmentCount;
16
+ // x-----x-----x-----x
17
+ // t= 0.33 0.66 1
18
+ // x-----o-----------x
19
+ // r= 0.33
20
+ // x-----o-----x
21
+ // r= 0.5 (0.33 / (1 - 0.33)) === tIncrement / (1 - (tIncrement * (i - 1))
22
+ // x-----x-----x-----x----x
23
+ // t= 0.25 0.5 0.75 1
24
+ // x-----o----------------x
25
+ // r= 0.25
26
+ // x-----o----------x
27
+ // r= 0.33 (0.25 / (1 - 0.25))
28
+ // x-----o----x
29
+ // r= 0.5 (0.25 / (1 - 0.5))
30
+ for (let i = 0; i < segmentCount - 1; i++) {
31
+ const tRelative = tIncrement / (1 - tIncrement * i);
32
+ const split = (0, de_casteljau_1.decasteljau)(remainingCurve, tRelative);
33
+ segments.push(split.left);
34
+ remainingCurve = split.right;
35
+ }
36
+ // last segment is just to the end from the last point
37
+ segments.push(remainingCurve);
38
+ return segments;
39
+ }
40
+ exports.splitCurveAsPoints = splitCurveAsPoints;
@@ -1,11 +1,11 @@
1
- import type { Command } from './command';
1
+ import type { CInstruction, LInstruction, QInstruction, ReducedInstruction } from '../helpers/types';
2
2
  /**
3
3
  * Convert command objects to arrays of points, run de Casteljau's algorithm on it
4
4
  * to split into to the desired number of segments.
5
5
  *
6
6
  * @param {Object} commandStart The start command object
7
- * @param {Object} commandEnd The end command object
7
+ * @param {Object} instructionEnd The end command object
8
8
  * @param {Number} segmentCount The number of segments to create
9
9
  * @return {Object[]} An array of commands representing the segments in sequence
10
10
  */
11
- export declare const splitCurve: (commandStartX: number, commandStartY: number, commandEnd: Command, segmentCount: number) => Command[];
11
+ export declare const splitCurveInstructions: (instructionStartX: number, instructionStartY: number, instructionEnd: LInstruction | QInstruction | CInstruction, segmentCount: number) => ReducedInstruction[];
@@ -32,134 +32,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
32
 
33
33
  */
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.splitCurve = void 0;
36
- /**
37
- * de Casteljau's algorithm for drawing and splitting bezier curves.
38
- * Inspired by https://pomax.github.io/bezierinfo/
39
- *
40
- * @param {Number[][]} points Array of [x,y] points: [start, control1, control2, ..., end]
41
- * The original segment to split.
42
- * @param {Number} t Where to split the curve (value between [0, 1])
43
- * @return {Object} An object { left, right } where left is the segment from 0..t and
44
- * right is the segment from t..1.
45
- */
46
- function decasteljau(points, t) {
47
- const left = [];
48
- const right = [];
49
- function decasteljauRecurse(_points, _t) {
50
- if (_points.length === 1) {
51
- left.push(_points[0]);
52
- right.push(_points[0]);
53
- }
54
- else {
55
- const newPoints = Array(_points.length - 1);
56
- for (let i = 0; i < newPoints.length; i++) {
57
- if (i === 0) {
58
- left.push(_points[0]);
59
- }
60
- if (i === newPoints.length - 1) {
61
- right.push(_points[i + 1]);
62
- }
63
- newPoints[i] = [
64
- (1 - _t) * _points[i][0] + _t * _points[i + 1][0],
65
- (1 - _t) * _points[i][1] + _t * _points[i + 1][1],
66
- ];
67
- }
68
- decasteljauRecurse(newPoints, _t);
69
- }
70
- }
71
- if (points.length) {
72
- decasteljauRecurse(points, t);
73
- }
74
- return { left, right: right.reverse() };
75
- }
76
- /**
77
- * Convert segments represented as points back into a command object
78
- *
79
- * @param {Number[][]} points Array of [x,y] points: [start, control1, control2, ..., end]
80
- * Represents a segment
81
- * @return {Object} A command object representing the segment.
82
- */
83
- function pointsToCommand(points) {
84
- let x2;
85
- let y2;
86
- let x1;
87
- let y1;
88
- if (points.length === 4) {
89
- x2 = points[2][0];
90
- y2 = points[2][1];
91
- }
92
- if (points.length >= 3) {
93
- x1 = points[1][0];
94
- y1 = points[1][1];
95
- }
96
- const x = points[points.length - 1][0];
97
- const y = points[points.length - 1][1];
98
- let type = 'L';
99
- if (points.length === 4) {
100
- // start, control1, control2, end
101
- type = 'C';
102
- }
103
- else if (points.length === 3) {
104
- // start, control, end
105
- type = 'Q';
106
- }
107
- return { x2, y2, x1, y1, x, y, type };
108
- }
109
- /**
110
- * Runs de Casteljau's algorithm enough times to produce the desired number of segments.
111
- *
112
- * @param {Number[][]} points Array of [x,y] points for de Casteljau (the initial segment to split)
113
- * @param {Number} segmentCount Number of segments to split the original into
114
- * @return {Number[][][]} Array of segments
115
- */
116
- function splitCurveAsPoints(points, segmentCount) {
117
- segmentCount = segmentCount || 2;
118
- const segments = [];
119
- let remainingCurve = points;
120
- const tIncrement = 1 / segmentCount;
121
- // x-----x-----x-----x
122
- // t= 0.33 0.66 1
123
- // x-----o-----------x
124
- // r= 0.33
125
- // x-----o-----x
126
- // r= 0.5 (0.33 / (1 - 0.33)) === tIncrement / (1 - (tIncrement * (i - 1))
127
- // x-----x-----x-----x----x
128
- // t= 0.25 0.5 0.75 1
129
- // x-----o----------------x
130
- // r= 0.25
131
- // x-----o----------x
132
- // r= 0.33 (0.25 / (1 - 0.25))
133
- // x-----o----x
134
- // r= 0.5 (0.25 / (1 - 0.5))
135
- for (let i = 0; i < segmentCount - 1; i++) {
136
- const tRelative = tIncrement / (1 - tIncrement * i);
137
- const split = decasteljau(remainingCurve, tRelative);
138
- segments.push(split.left);
139
- remainingCurve = split.right;
140
- }
141
- // last segment is just to the end from the last point
142
- segments.push(remainingCurve);
143
- return segments;
144
- }
35
+ exports.splitCurveInstructions = void 0;
36
+ const points_to_command_1 = require("./points-to-command");
37
+ const split_curve_as_points_1 = require("./split-curve-as-points");
145
38
  /**
146
39
  * Convert command objects to arrays of points, run de Casteljau's algorithm on it
147
40
  * to split into to the desired number of segments.
148
41
  *
149
42
  * @param {Object} commandStart The start command object
150
- * @param {Object} commandEnd The end command object
43
+ * @param {Object} instructionEnd The end command object
151
44
  * @param {Number} segmentCount The number of segments to create
152
45
  * @return {Object[]} An array of commands representing the segments in sequence
153
46
  */
154
- const splitCurve = (commandStartX, commandStartY, commandEnd, segmentCount) => {
155
- const points = [[commandStartX, commandStartY]];
156
- if (commandEnd.x1 !== null && commandEnd.x1 !== undefined) {
157
- points.push([commandEnd.x1, commandEnd.y1]);
158
- }
159
- if (commandEnd.x2 !== null && commandEnd.x2 !== undefined) {
160
- points.push([commandEnd.x2, commandEnd.y2]);
161
- }
162
- points.push([commandEnd.x, commandEnd.y]);
163
- return splitCurveAsPoints(points, segmentCount).map(pointsToCommand);
47
+ const splitCurveInstructions = (instructionStartX, instructionStartY, instructionEnd, segmentCount) => {
48
+ const points = [[instructionStartX, instructionStartY]];
49
+ if (instructionEnd.type === 'Q') {
50
+ points.push([instructionEnd.cpx, instructionEnd.cpy]);
51
+ }
52
+ if (instructionEnd.type === 'C') {
53
+ points.push([instructionEnd.cp1x, instructionEnd.cp1y]);
54
+ points.push([instructionEnd.cp2x, instructionEnd.cp2y]);
55
+ }
56
+ points.push([instructionEnd.x, instructionEnd.y]);
57
+ return (0, split_curve_as_points_1.splitCurveAsPoints)(points, segmentCount).map((p) => {
58
+ return (0, points_to_command_1.pointsToInstruction)(p);
59
+ });
164
60
  };
165
- exports.splitCurve = splitCurve;
61
+ exports.splitCurveInstructions = splitCurveInstructions;
@@ -1,4 +1,4 @@
1
- import type { Command } from './command';
1
+ import type { ReducedInstruction } from '../helpers/types';
2
2
  /**
3
3
  * Interpolate between command objects commandStart and commandEnd segmentCount times.
4
4
  * If the types are L, Q, or C then the curves are split as per de Casteljau's algorithm.
@@ -11,4 +11,4 @@ import type { Command } from './command';
11
11
  * @return {Object[]} Array of ~segmentCount command objects between commandStart and
12
12
  * commandEnd. (Can be segmentCount+1 objects if commandStart is type M).
13
13
  */
14
- export declare function splitSegment(commandStart: Command, commandEnd: Command, segmentCount: number): Command[];
14
+ export declare function splitSegmentInstructions(commandStart: ReducedInstruction, commandEnd: ReducedInstruction, segmentCount: number): ReducedInstruction[];
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.splitSegment = void 0;
4
- const array_of_length_1 = require("./array-of-length");
3
+ exports.splitSegmentInstructions = void 0;
5
4
  const split_curve_1 = require("./split-curve");
6
5
  /**
7
6
  * Interpolate between command objects commandStart and commandEnd segmentCount times.
@@ -15,27 +14,28 @@ const split_curve_1 = require("./split-curve");
15
14
  * @return {Object[]} Array of ~segmentCount command objects between commandStart and
16
15
  * commandEnd. (Can be segmentCount+1 objects if commandStart is type M).
17
16
  */
18
- // TODO: Delete and replace
19
- function splitSegment(commandStart, commandEnd, segmentCount) {
17
+ function splitSegmentInstructions(commandStart, commandEnd, segmentCount) {
20
18
  let segments = [];
21
19
  // line, quadratic bezier, or cubic bezier
22
20
  if (commandEnd.type === 'L' ||
23
21
  commandEnd.type === 'Q' ||
24
22
  commandEnd.type === 'C') {
25
23
  if (commandStart.type !== 'Z') {
26
- segments = segments.concat((0, split_curve_1.splitCurve)(commandStart.x, commandStart.y, commandEnd, segmentCount));
24
+ segments = segments.concat((0, split_curve_1.splitCurveInstructions)(commandStart.x, commandStart.y, commandEnd, segmentCount));
27
25
  }
28
26
  // general case - just copy the same point
29
27
  }
30
28
  else {
31
- const copyCommand = { ...commandStart };
32
- // convert M to L
33
- if (copyCommand.type === 'M') {
34
- copyCommand.type = 'L';
35
- }
36
- segments = segments.concat((0, array_of_length_1.arrayOfLength)(segmentCount - 1, undefined).map(() => copyCommand));
29
+ const copyCommand = commandStart.type === 'M'
30
+ ? {
31
+ type: 'L',
32
+ x: commandStart.x,
33
+ y: commandStart.y,
34
+ }
35
+ : commandStart;
36
+ segments = segments.concat(new Array(segmentCount - 1).fill(true).map(() => copyCommand));
37
37
  segments.push(commandEnd);
38
38
  }
39
39
  return segments;
40
40
  }
41
- exports.splitSegment = splitSegment;
41
+ exports.splitSegmentInstructions = splitSegmentInstructions;