@remotion/paths 3.3.44 → 3.3.51
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.
- package/package.json +2 -2
- package/dist/helpers/parse.d.ts +0 -2
- package/dist/helpers/parse.js +0 -51
- package/dist/helpers/serialize.d.ts +0 -2
- package/dist/helpers/serialize.js +0 -75
- package/dist/helpers/unarc.d.ts +0 -2
- package/dist/helpers/unarc.js +0 -254
- package/dist/helpers/unshort.d.ts +0 -2
- package/dist/helpers/unshort.js +0 -65
- package/dist/parse.d.ts +0 -2
- package/dist/parse.js +0 -266
- package/dist/serialize.d.ts +0 -2
- package/dist/serialize.js +0 -75
- package/dist/simplify-instructions.d.ts +0 -2
- package/dist/simplify-instructions.js +0 -10
- package/dist/unarc.d.ts +0 -2
- package/dist/unarc.js +0 -180
- package/dist/unshort.d.ts +0 -2
- package/dist/unshort.js +0 -118
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/paths",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.51",
|
|
4
4
|
"description": "Utility functions for SVG paths",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "be64134aece51abd6c63e644702517c868d6c8d0"
|
|
39
39
|
}
|
package/dist/helpers/parse.d.ts
DELETED
package/dist/helpers/parse.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Copied from: https://github.com/rveciana/svg-path-properties
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.parsePath = void 0;
|
|
5
|
-
const length = {
|
|
6
|
-
a: 7,
|
|
7
|
-
c: 6,
|
|
8
|
-
h: 1,
|
|
9
|
-
l: 2,
|
|
10
|
-
m: 2,
|
|
11
|
-
q: 4,
|
|
12
|
-
s: 4,
|
|
13
|
-
t: 2,
|
|
14
|
-
v: 1,
|
|
15
|
-
z: 0,
|
|
16
|
-
};
|
|
17
|
-
const segmentRegExp = /([astvzqmhlc])([^astvzqmhlc]*)/gi;
|
|
18
|
-
const numberRegExp = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;
|
|
19
|
-
const parsePath = (path) => {
|
|
20
|
-
const segments = (path && path.length > 0 ? path : 'M0,0').match(segmentRegExp);
|
|
21
|
-
if (!segments) {
|
|
22
|
-
throw new Error(`No path elements found in string ${path}`);
|
|
23
|
-
}
|
|
24
|
-
return segments.reduce((segmentsArray, segmentString) => {
|
|
25
|
-
let command = segmentString.charAt(0);
|
|
26
|
-
let type = command.toLowerCase();
|
|
27
|
-
const args = parseValues(segmentString.substr(1));
|
|
28
|
-
// overloaded moveTo
|
|
29
|
-
if (type === 'm' && args.length > 2) {
|
|
30
|
-
segmentsArray.push([command, ...args.splice(0, 2)]);
|
|
31
|
-
type = 'l';
|
|
32
|
-
command = command === 'm' ? 'l' : 'L';
|
|
33
|
-
}
|
|
34
|
-
while (args.length >= 0) {
|
|
35
|
-
if (args.length === length[type]) {
|
|
36
|
-
segmentsArray.push([command, ...args.splice(0, length[type])]);
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
if (args.length < length[type]) {
|
|
40
|
-
throw new Error(`Malformed path data: "${command}" must have ${length[type]} elements and has ${args.length}: ${segmentString}`);
|
|
41
|
-
}
|
|
42
|
-
segmentsArray.push([command, ...args.splice(0, length[type])]);
|
|
43
|
-
}
|
|
44
|
-
return segmentsArray;
|
|
45
|
-
}, []);
|
|
46
|
-
};
|
|
47
|
-
exports.parsePath = parsePath;
|
|
48
|
-
const parseValues = (args) => {
|
|
49
|
-
const numbers = args.match(numberRegExp);
|
|
50
|
-
return numbers ? numbers.map(Number) : [];
|
|
51
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.serializeInstructions = void 0;
|
|
4
|
-
const serializeInstruction = (instruction) => {
|
|
5
|
-
if (instruction.type === 'A') {
|
|
6
|
-
return `A ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.x} ${instruction.y}`;
|
|
7
|
-
}
|
|
8
|
-
if (instruction.type === 'a') {
|
|
9
|
-
return `a ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.dx} ${instruction.dy}`;
|
|
10
|
-
}
|
|
11
|
-
if (instruction.type === 'C') {
|
|
12
|
-
return `C ${instruction.cp1x} ${instruction.cp1y} ${instruction.cp2x} ${instruction.cp2y} ${instruction.x} ${instruction.y}`;
|
|
13
|
-
}
|
|
14
|
-
if (instruction.type === 'c') {
|
|
15
|
-
return `c ${instruction.cp1dx} ${instruction.cp1dy} ${instruction.cp2dx} ${instruction.cp2dy} ${instruction.dx} ${instruction.dy}`;
|
|
16
|
-
}
|
|
17
|
-
if (instruction.type === 'S') {
|
|
18
|
-
return `S ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
|
|
19
|
-
}
|
|
20
|
-
if (instruction.type === 's') {
|
|
21
|
-
return `s ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
|
|
22
|
-
}
|
|
23
|
-
if (instruction.type === 'Q') {
|
|
24
|
-
return `Q ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
|
|
25
|
-
}
|
|
26
|
-
if (instruction.type === 'q') {
|
|
27
|
-
return `q ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
|
|
28
|
-
}
|
|
29
|
-
if (instruction.type === 'z') {
|
|
30
|
-
return 'z';
|
|
31
|
-
}
|
|
32
|
-
if (instruction.type === 'Z') {
|
|
33
|
-
return 'Z';
|
|
34
|
-
}
|
|
35
|
-
if (instruction.type === 'H') {
|
|
36
|
-
return `H ${instruction.x}`;
|
|
37
|
-
}
|
|
38
|
-
if (instruction.type === 'h') {
|
|
39
|
-
return `h ${instruction.dx}`;
|
|
40
|
-
}
|
|
41
|
-
if (instruction.type === 'V') {
|
|
42
|
-
return `V ${instruction.y}`;
|
|
43
|
-
}
|
|
44
|
-
if (instruction.type === 'v') {
|
|
45
|
-
return `v ${instruction.dy}`;
|
|
46
|
-
}
|
|
47
|
-
if (instruction.type === 'L') {
|
|
48
|
-
return `L ${instruction.x} ${instruction.y}`;
|
|
49
|
-
}
|
|
50
|
-
if (instruction.type === 'l') {
|
|
51
|
-
return `l ${instruction.dx} ${instruction.dy}`;
|
|
52
|
-
}
|
|
53
|
-
if (instruction.type === 'M') {
|
|
54
|
-
return `M ${instruction.x} ${instruction.y}`;
|
|
55
|
-
}
|
|
56
|
-
if (instruction.type === 'm') {
|
|
57
|
-
return `m ${instruction.dx} ${instruction.dy}`;
|
|
58
|
-
}
|
|
59
|
-
if (instruction.type === 'T') {
|
|
60
|
-
return `T ${instruction.x} ${instruction.y}`;
|
|
61
|
-
}
|
|
62
|
-
if (instruction.type === 't') {
|
|
63
|
-
return `t ${instruction.dx} ${instruction.dy}`;
|
|
64
|
-
}
|
|
65
|
-
// @ts-expect-error
|
|
66
|
-
throw new Error(`Unknown instruction type: ${instruction.type}`);
|
|
67
|
-
};
|
|
68
|
-
const serializeInstructions = (path) => {
|
|
69
|
-
return path
|
|
70
|
-
.map((p) => {
|
|
71
|
-
return serializeInstruction(p);
|
|
72
|
-
})
|
|
73
|
-
.join(' ');
|
|
74
|
-
};
|
|
75
|
-
exports.serializeInstructions = serializeInstructions;
|
package/dist/helpers/unarc.d.ts
DELETED
package/dist/helpers/unarc.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.removeArcInstructions = void 0;
|
|
4
|
-
const iterate_1 = require("./iterate");
|
|
5
|
-
const TAU = Math.PI * 2;
|
|
6
|
-
function approximate_unit_arc(theta1, delta_theta) {
|
|
7
|
-
const alpha = (4 / 3) * Math.tan(delta_theta / 4);
|
|
8
|
-
const x1 = Math.cos(theta1);
|
|
9
|
-
const y1 = Math.sin(theta1);
|
|
10
|
-
const x2 = Math.cos(theta1 + delta_theta);
|
|
11
|
-
const y2 = Math.sin(theta1 + delta_theta);
|
|
12
|
-
return [
|
|
13
|
-
x1,
|
|
14
|
-
y1,
|
|
15
|
-
x1 - y1 * alpha,
|
|
16
|
-
y1 + x1 * alpha,
|
|
17
|
-
x2 + y2 * alpha,
|
|
18
|
-
y2 - x2 * alpha,
|
|
19
|
-
x2,
|
|
20
|
-
y2,
|
|
21
|
-
];
|
|
22
|
-
}
|
|
23
|
-
function arcToCircle({ x1, y1, x2, y2, largeArcFlag, sweepFlag, rx, ry, phi, }) {
|
|
24
|
-
const sin_phi = Math.sin((phi * TAU) / 360);
|
|
25
|
-
const cos_phi = Math.cos((phi * TAU) / 360);
|
|
26
|
-
// Make sure radii are valid
|
|
27
|
-
//
|
|
28
|
-
const x1p = (cos_phi * (x1 - x2)) / 2 + (sin_phi * (y1 - y2)) / 2;
|
|
29
|
-
const y1p = (-sin_phi * (x1 - x2)) / 2 + (cos_phi * (y1 - y2)) / 2;
|
|
30
|
-
if (x1p === 0 && y1p === 0) {
|
|
31
|
-
// we're asked to draw line to itself
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
|
-
if (rx === 0 || ry === 0) {
|
|
35
|
-
// one of the radii is zero
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
// Compensate out-of-range radii
|
|
39
|
-
//
|
|
40
|
-
rx = Math.abs(rx);
|
|
41
|
-
ry = Math.abs(ry);
|
|
42
|
-
const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
|
|
43
|
-
if (lambda > 1) {
|
|
44
|
-
rx *= Math.sqrt(lambda);
|
|
45
|
-
ry *= Math.sqrt(lambda);
|
|
46
|
-
}
|
|
47
|
-
// Get center parameters (cx, cy, theta1, delta_theta)
|
|
48
|
-
//
|
|
49
|
-
const cc = get_arc_center({
|
|
50
|
-
x1,
|
|
51
|
-
y1,
|
|
52
|
-
x2,
|
|
53
|
-
y2,
|
|
54
|
-
largeArcFlag,
|
|
55
|
-
sweepFlag,
|
|
56
|
-
rx,
|
|
57
|
-
ry,
|
|
58
|
-
sin_phi,
|
|
59
|
-
cos_phi,
|
|
60
|
-
});
|
|
61
|
-
const result = [];
|
|
62
|
-
let theta1 = cc[2];
|
|
63
|
-
let delta_theta = cc[3];
|
|
64
|
-
// Split an arc to multiple segments, so each segment
|
|
65
|
-
// will be less than τ/4 (= 90°)
|
|
66
|
-
//
|
|
67
|
-
const segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
|
|
68
|
-
delta_theta /= segments;
|
|
69
|
-
for (let i = 0; i < segments; i++) {
|
|
70
|
-
result.push(approximate_unit_arc(theta1, delta_theta));
|
|
71
|
-
theta1 += delta_theta;
|
|
72
|
-
}
|
|
73
|
-
// We have a bezier approximation of a unit circle,
|
|
74
|
-
// now need to transform back to the original ellipse
|
|
75
|
-
//
|
|
76
|
-
return result.map((curve) => {
|
|
77
|
-
for (let i = 0; i < curve.length; i += 2) {
|
|
78
|
-
let x = curve[i + 0];
|
|
79
|
-
let y = curve[i + 1];
|
|
80
|
-
// scale
|
|
81
|
-
x *= rx;
|
|
82
|
-
y *= ry;
|
|
83
|
-
// rotate
|
|
84
|
-
const xp = cos_phi * x - sin_phi * y;
|
|
85
|
-
const yp = sin_phi * x + cos_phi * y;
|
|
86
|
-
// translate
|
|
87
|
-
curve[i + 0] = xp + cc[0];
|
|
88
|
-
curve[i + 1] = yp + cc[1];
|
|
89
|
-
}
|
|
90
|
-
return curve;
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
// Requires path to be normalized
|
|
94
|
-
const removeArcInstructions = (segments) => {
|
|
95
|
-
let prevControlX = 0;
|
|
96
|
-
let prevControlY = 0;
|
|
97
|
-
let curControlX = 0;
|
|
98
|
-
let curControlY = 0;
|
|
99
|
-
return (0, iterate_1.iterateOverSegments)({
|
|
100
|
-
segments,
|
|
101
|
-
iterate: ({ segment, prevSegment, x, y }) => {
|
|
102
|
-
if (segment.type === 'A') {
|
|
103
|
-
const nextX = segment.x;
|
|
104
|
-
const nextY = segment.y;
|
|
105
|
-
const new_segments = arcToCircle({
|
|
106
|
-
x1: x,
|
|
107
|
-
y1: y,
|
|
108
|
-
x2: nextX,
|
|
109
|
-
y2: nextY,
|
|
110
|
-
largeArcFlag: segment.largeArcFlag,
|
|
111
|
-
sweepFlag: segment.sweepFlag,
|
|
112
|
-
rx: segment.rx,
|
|
113
|
-
ry: segment.ry,
|
|
114
|
-
phi: segment.xAxisRotation,
|
|
115
|
-
});
|
|
116
|
-
// Degenerated arcs can be ignored by renderer, but should not be dropped
|
|
117
|
-
// to avoid collisions with `S A S` and so on. Replace with empty line.
|
|
118
|
-
if (new_segments.length === 0) {
|
|
119
|
-
return [
|
|
120
|
-
{
|
|
121
|
-
type: 'L',
|
|
122
|
-
x: segment.x,
|
|
123
|
-
y: segment.y,
|
|
124
|
-
},
|
|
125
|
-
];
|
|
126
|
-
}
|
|
127
|
-
const result = new_segments.map((_s) => {
|
|
128
|
-
return {
|
|
129
|
-
type: 'C',
|
|
130
|
-
cp1x: _s[2],
|
|
131
|
-
cp1y: _s[3],
|
|
132
|
-
cp2x: _s[4],
|
|
133
|
-
cp2y: _s[5],
|
|
134
|
-
x: _s[6],
|
|
135
|
-
y: _s[7],
|
|
136
|
-
};
|
|
137
|
-
});
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
if (segment.type === 'T') {
|
|
141
|
-
if (prevSegment && prevSegment.type === 'Q') {
|
|
142
|
-
prevControlX = prevSegment.cpx;
|
|
143
|
-
prevControlY = prevSegment.cpy;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
prevControlX = 0;
|
|
147
|
-
prevControlY = 0;
|
|
148
|
-
}
|
|
149
|
-
curControlX = -prevControlX;
|
|
150
|
-
curControlY = -prevControlY;
|
|
151
|
-
return [
|
|
152
|
-
{
|
|
153
|
-
type: 'Q',
|
|
154
|
-
cpx: curControlX,
|
|
155
|
-
cpy: curControlY,
|
|
156
|
-
x: segment.x,
|
|
157
|
-
y: segment.y,
|
|
158
|
-
},
|
|
159
|
-
];
|
|
160
|
-
}
|
|
161
|
-
if (segment.type === 'S') {
|
|
162
|
-
if (prevSegment && prevSegment.type === 'C') {
|
|
163
|
-
prevControlX = prevSegment.cp2x;
|
|
164
|
-
prevControlY = prevSegment.cp2y;
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
prevControlX = 0;
|
|
168
|
-
prevControlY = 0;
|
|
169
|
-
}
|
|
170
|
-
curControlX = -prevControlX;
|
|
171
|
-
curControlY = -prevControlY;
|
|
172
|
-
return [
|
|
173
|
-
{
|
|
174
|
-
type: 'C',
|
|
175
|
-
cp1x: curControlX,
|
|
176
|
-
cp1y: curControlY,
|
|
177
|
-
cp2x: segment.cpx,
|
|
178
|
-
cp2y: segment.cpy,
|
|
179
|
-
x: segment.x,
|
|
180
|
-
y: segment.y,
|
|
181
|
-
},
|
|
182
|
-
];
|
|
183
|
-
}
|
|
184
|
-
return [segment];
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
};
|
|
188
|
-
exports.removeArcInstructions = removeArcInstructions;
|
|
189
|
-
function get_arc_center({ x1, y1, x2, y2, largeArcFlag, sweepFlag, rx, ry, sin_phi, cos_phi, }) {
|
|
190
|
-
// Step 1.
|
|
191
|
-
//
|
|
192
|
-
// Moving an ellipse so origin will be the middlepoint between our two
|
|
193
|
-
// points. After that, rotate it to line up ellipse axes with coordinate
|
|
194
|
-
// axes.
|
|
195
|
-
//
|
|
196
|
-
const x1p = (cos_phi * (x1 - x2)) / 2 + (sin_phi * (y1 - y2)) / 2;
|
|
197
|
-
const y1p = (-sin_phi * (x1 - x2)) / 2 + (cos_phi * (y1 - y2)) / 2;
|
|
198
|
-
const rx_sq = rx * rx;
|
|
199
|
-
const ry_sq = ry * ry;
|
|
200
|
-
const x1p_sq = x1p * x1p;
|
|
201
|
-
const y1p_sq = y1p * y1p;
|
|
202
|
-
// Step 2.
|
|
203
|
-
//
|
|
204
|
-
// Compute coordinates of the centre of this ellipse (cx', cy')
|
|
205
|
-
// in the new coordinate system.
|
|
206
|
-
//
|
|
207
|
-
let radicant = rx_sq * ry_sq - rx_sq * y1p_sq - ry_sq * x1p_sq;
|
|
208
|
-
if (radicant < 0) {
|
|
209
|
-
// due to rounding errors it might be e.g. -1.3877787807814457e-17
|
|
210
|
-
radicant = 0;
|
|
211
|
-
}
|
|
212
|
-
radicant /= rx_sq * y1p_sq + ry_sq * x1p_sq;
|
|
213
|
-
radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1);
|
|
214
|
-
const cxp = ((radicant * rx) / ry) * y1p;
|
|
215
|
-
const cyp = ((radicant * -ry) / rx) * x1p;
|
|
216
|
-
// Step 3.
|
|
217
|
-
//
|
|
218
|
-
// Transform back to get centre coordinates (cx, cy) in the original
|
|
219
|
-
// coordinate system.
|
|
220
|
-
//
|
|
221
|
-
const cx = cos_phi * cxp - sin_phi * cyp + (x1 + x2) / 2;
|
|
222
|
-
const cy = sin_phi * cxp + cos_phi * cyp + (y1 + y2) / 2;
|
|
223
|
-
// Step 4.
|
|
224
|
-
//
|
|
225
|
-
// Compute angles (theta1, delta_theta).
|
|
226
|
-
//
|
|
227
|
-
const v1x = (x1p - cxp) / rx;
|
|
228
|
-
const v1y = (y1p - cyp) / ry;
|
|
229
|
-
const v2x = (-x1p - cxp) / rx;
|
|
230
|
-
const v2y = (-y1p - cyp) / ry;
|
|
231
|
-
const theta1 = unit_vector_angle(1, 0, v1x, v1y);
|
|
232
|
-
let delta_theta = unit_vector_angle(v1x, v1y, v2x, v2y);
|
|
233
|
-
if (sweepFlag === false && delta_theta > 0) {
|
|
234
|
-
delta_theta -= TAU;
|
|
235
|
-
}
|
|
236
|
-
if (sweepFlag === true && delta_theta < 0) {
|
|
237
|
-
delta_theta += TAU;
|
|
238
|
-
}
|
|
239
|
-
return [cx, cy, theta1, delta_theta];
|
|
240
|
-
}
|
|
241
|
-
function unit_vector_angle(ux, uy, vx, vy) {
|
|
242
|
-
const sign = ux * vy - uy * vx < 0 ? -1 : 1;
|
|
243
|
-
let dot = ux * vx + uy * vy;
|
|
244
|
-
// Add this to work with arbitrary vectors:
|
|
245
|
-
// dot /= Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
|
|
246
|
-
// rounding errors, e.g. -1.0000000000000002 can screw up this
|
|
247
|
-
if (dot > 1.0) {
|
|
248
|
-
dot = 1.0;
|
|
249
|
-
}
|
|
250
|
-
if (dot < -1.0) {
|
|
251
|
-
dot = -1.0;
|
|
252
|
-
}
|
|
253
|
-
return sign * Math.acos(dot);
|
|
254
|
-
}
|
package/dist/helpers/unshort.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unshort = void 0;
|
|
4
|
-
// Requires that the path is already normalized
|
|
5
|
-
const unshort = function (segments) {
|
|
6
|
-
let prevControlX = 0;
|
|
7
|
-
let prevControlY = 0;
|
|
8
|
-
let curControlX = 0;
|
|
9
|
-
let curControlY = 0;
|
|
10
|
-
const newSegments = segments.slice(0);
|
|
11
|
-
for (let i = 0; i < newSegments.length; i++) {
|
|
12
|
-
const s = newSegments[i];
|
|
13
|
-
// First command MUST be M|m, it's safe to skip.
|
|
14
|
-
// Protect from access to [-1] for sure.
|
|
15
|
-
if (!i) {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
if (s.type === 'T') {
|
|
19
|
-
// quadratic curve
|
|
20
|
-
const prevSegment = newSegments[i - 1];
|
|
21
|
-
if (prevSegment.type === 'Q') {
|
|
22
|
-
prevControlX = prevSegment.cpx;
|
|
23
|
-
prevControlY = prevSegment.cpy;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
prevControlX = 0;
|
|
27
|
-
prevControlY = 0;
|
|
28
|
-
}
|
|
29
|
-
curControlX = -prevControlX;
|
|
30
|
-
curControlY = -prevControlY;
|
|
31
|
-
newSegments[i] = {
|
|
32
|
-
type: 'Q',
|
|
33
|
-
cpx: curControlX,
|
|
34
|
-
cpy: curControlY,
|
|
35
|
-
x: s.x,
|
|
36
|
-
y: s.y,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
else if (s.type === 'S') {
|
|
40
|
-
// cubic curve
|
|
41
|
-
const prevSegment = newSegments[i - 1];
|
|
42
|
-
if (prevSegment.type === 'C') {
|
|
43
|
-
prevControlX = prevSegment.cp2x;
|
|
44
|
-
prevControlY = prevSegment.cp2y;
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
prevControlX = 0;
|
|
48
|
-
prevControlY = 0;
|
|
49
|
-
}
|
|
50
|
-
curControlX = -prevControlX;
|
|
51
|
-
curControlY = -prevControlY;
|
|
52
|
-
newSegments[i] = {
|
|
53
|
-
type: 'C',
|
|
54
|
-
cp1x: curControlX,
|
|
55
|
-
cp1y: curControlY,
|
|
56
|
-
cp2x: s.cpx,
|
|
57
|
-
cp2y: s.cpy,
|
|
58
|
-
x: s.x,
|
|
59
|
-
y: s.y,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return newSegments;
|
|
64
|
-
};
|
|
65
|
-
exports.unshort = unshort;
|
package/dist/parse.d.ts
DELETED
package/dist/parse.js
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Copied from: https://github.com/rveciana/svg-path-properties
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.parsePath = void 0;
|
|
5
|
-
const length = {
|
|
6
|
-
a: 7,
|
|
7
|
-
A: 7,
|
|
8
|
-
C: 6,
|
|
9
|
-
c: 6,
|
|
10
|
-
H: 1,
|
|
11
|
-
h: 1,
|
|
12
|
-
L: 2,
|
|
13
|
-
l: 2,
|
|
14
|
-
M: 2,
|
|
15
|
-
m: 2,
|
|
16
|
-
Q: 4,
|
|
17
|
-
q: 4,
|
|
18
|
-
S: 4,
|
|
19
|
-
s: 4,
|
|
20
|
-
T: 2,
|
|
21
|
-
t: 2,
|
|
22
|
-
V: 1,
|
|
23
|
-
v: 1,
|
|
24
|
-
Z: 0,
|
|
25
|
-
z: 0,
|
|
26
|
-
};
|
|
27
|
-
const chunkExact = (array, instruction) => {
|
|
28
|
-
const chunks = [];
|
|
29
|
-
const expectedSize = length[instruction];
|
|
30
|
-
if (array.length % expectedSize !== 0) {
|
|
31
|
-
throw new Error(`Expected number of arguments of SVG instruction "${instruction} ${array.join(' ')}" to be a multiple of ${expectedSize}`);
|
|
32
|
-
}
|
|
33
|
-
for (let i = 0; i < array.length; i += expectedSize) {
|
|
34
|
-
chunks.push(array.slice(i, i + expectedSize));
|
|
35
|
-
}
|
|
36
|
-
return chunks;
|
|
37
|
-
};
|
|
38
|
-
const makeInstructions = (arr, instruction, cb) => {
|
|
39
|
-
return chunkExact(arr, instruction).map((args) => {
|
|
40
|
-
return cb(args);
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
const segmentRegExp = /([astvzqmhlc])([^astvzqmhlc]*)/gi;
|
|
44
|
-
const numberRegExp = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;
|
|
45
|
-
const parsePath = (path) => {
|
|
46
|
-
if (!path) {
|
|
47
|
-
throw new Error('No path provided');
|
|
48
|
-
}
|
|
49
|
-
const segments = path.match(segmentRegExp);
|
|
50
|
-
if (!segments) {
|
|
51
|
-
throw new Error(`No path elements found in string ${path}`);
|
|
52
|
-
}
|
|
53
|
-
return segments
|
|
54
|
-
.map((segmentString) => {
|
|
55
|
-
const command = segmentString.charAt(0);
|
|
56
|
-
const args = parseValues(segmentString.substring(1), command);
|
|
57
|
-
// overloaded moveTo
|
|
58
|
-
if (command === 'M' && args.length > 2) {
|
|
59
|
-
const segmentsArray = [];
|
|
60
|
-
segmentsArray.push({
|
|
61
|
-
type: command,
|
|
62
|
-
x: args[0],
|
|
63
|
-
y: args[1],
|
|
64
|
-
});
|
|
65
|
-
segmentsArray.push(...makeInstructions(args.slice(2), 'L', (numbers) => ({
|
|
66
|
-
type: 'L',
|
|
67
|
-
x: numbers[0],
|
|
68
|
-
y: numbers[1],
|
|
69
|
-
})));
|
|
70
|
-
return segmentsArray;
|
|
71
|
-
}
|
|
72
|
-
if (command === 'm' && args.length > 2) {
|
|
73
|
-
const segmentsArray = [];
|
|
74
|
-
segmentsArray.push({
|
|
75
|
-
type: command,
|
|
76
|
-
dx: args[0],
|
|
77
|
-
dy: args[1],
|
|
78
|
-
});
|
|
79
|
-
segmentsArray.push(...makeInstructions(args.slice(2), 'l', (numbers) => ({
|
|
80
|
-
type: 'l',
|
|
81
|
-
dx: numbers[0],
|
|
82
|
-
dy: numbers[1],
|
|
83
|
-
})));
|
|
84
|
-
return segmentsArray;
|
|
85
|
-
}
|
|
86
|
-
if (command === 'Z') {
|
|
87
|
-
return [
|
|
88
|
-
{
|
|
89
|
-
type: 'Z',
|
|
90
|
-
},
|
|
91
|
-
];
|
|
92
|
-
}
|
|
93
|
-
if (command === 'z') {
|
|
94
|
-
return [
|
|
95
|
-
{
|
|
96
|
-
type: 'z',
|
|
97
|
-
},
|
|
98
|
-
];
|
|
99
|
-
}
|
|
100
|
-
if (command === 'A') {
|
|
101
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
102
|
-
type: command,
|
|
103
|
-
rx: numbers[0],
|
|
104
|
-
ry: numbers[1],
|
|
105
|
-
xAxisRotation: numbers[2],
|
|
106
|
-
largeArcFlag: numbers[3] === 1,
|
|
107
|
-
sweepFlag: numbers[4] === 1,
|
|
108
|
-
x: numbers[5],
|
|
109
|
-
y: numbers[6],
|
|
110
|
-
}));
|
|
111
|
-
}
|
|
112
|
-
if (command === 'a') {
|
|
113
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
114
|
-
type: command,
|
|
115
|
-
rx: numbers[0],
|
|
116
|
-
ry: numbers[1],
|
|
117
|
-
xAxisRotation: numbers[2],
|
|
118
|
-
largeArcFlag: numbers[3] === 1,
|
|
119
|
-
sweepFlag: numbers[4] === 1,
|
|
120
|
-
dx: numbers[5],
|
|
121
|
-
dy: numbers[6],
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
|
-
if (command === 'C') {
|
|
125
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
126
|
-
type: command,
|
|
127
|
-
cp1x: numbers[0],
|
|
128
|
-
cp1y: numbers[1],
|
|
129
|
-
cp2x: numbers[2],
|
|
130
|
-
cp2y: numbers[3],
|
|
131
|
-
x: numbers[4],
|
|
132
|
-
y: numbers[5],
|
|
133
|
-
}));
|
|
134
|
-
}
|
|
135
|
-
if (command === 'c') {
|
|
136
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
137
|
-
type: command,
|
|
138
|
-
cp1dx: numbers[0],
|
|
139
|
-
cp1dy: numbers[1],
|
|
140
|
-
cp2dx: numbers[2],
|
|
141
|
-
cp2dy: numbers[3],
|
|
142
|
-
dx: numbers[4],
|
|
143
|
-
dy: numbers[5],
|
|
144
|
-
}));
|
|
145
|
-
}
|
|
146
|
-
if (command === 'S') {
|
|
147
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
148
|
-
type: command,
|
|
149
|
-
cpx: numbers[0],
|
|
150
|
-
cpy: numbers[1],
|
|
151
|
-
x: numbers[2],
|
|
152
|
-
y: numbers[3],
|
|
153
|
-
}));
|
|
154
|
-
}
|
|
155
|
-
if (command === 's') {
|
|
156
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
157
|
-
type: command,
|
|
158
|
-
cpdx: numbers[0],
|
|
159
|
-
cpdy: numbers[1],
|
|
160
|
-
dx: numbers[2],
|
|
161
|
-
dy: numbers[3],
|
|
162
|
-
}));
|
|
163
|
-
}
|
|
164
|
-
if (command === 'H') {
|
|
165
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
166
|
-
type: command,
|
|
167
|
-
x: numbers[0],
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
if (command === 'h') {
|
|
171
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
172
|
-
type: command,
|
|
173
|
-
dx: numbers[0],
|
|
174
|
-
}));
|
|
175
|
-
}
|
|
176
|
-
if (command === 'V') {
|
|
177
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
178
|
-
type: command,
|
|
179
|
-
y: numbers[0],
|
|
180
|
-
}));
|
|
181
|
-
}
|
|
182
|
-
if (command === 'v') {
|
|
183
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
184
|
-
type: command,
|
|
185
|
-
dy: numbers[0],
|
|
186
|
-
}));
|
|
187
|
-
}
|
|
188
|
-
if (command === 'L') {
|
|
189
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
190
|
-
type: command,
|
|
191
|
-
x: numbers[0],
|
|
192
|
-
y: numbers[1],
|
|
193
|
-
}));
|
|
194
|
-
}
|
|
195
|
-
if (command === 'M') {
|
|
196
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
197
|
-
type: command,
|
|
198
|
-
x: numbers[0],
|
|
199
|
-
y: numbers[1],
|
|
200
|
-
}));
|
|
201
|
-
}
|
|
202
|
-
if (command === 'm') {
|
|
203
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
204
|
-
type: command,
|
|
205
|
-
dx: numbers[0],
|
|
206
|
-
dy: numbers[1],
|
|
207
|
-
}));
|
|
208
|
-
}
|
|
209
|
-
if (command === 'l') {
|
|
210
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
211
|
-
type: command,
|
|
212
|
-
dx: numbers[0],
|
|
213
|
-
dy: numbers[1],
|
|
214
|
-
}));
|
|
215
|
-
}
|
|
216
|
-
if (command === 'Q') {
|
|
217
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
218
|
-
type: command,
|
|
219
|
-
cpx: numbers[0],
|
|
220
|
-
cpy: numbers[1],
|
|
221
|
-
x: numbers[2],
|
|
222
|
-
y: numbers[3],
|
|
223
|
-
}));
|
|
224
|
-
}
|
|
225
|
-
if (command === 'q') {
|
|
226
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
227
|
-
type: command,
|
|
228
|
-
cpdx: numbers[0],
|
|
229
|
-
cpdy: numbers[1],
|
|
230
|
-
dx: numbers[2],
|
|
231
|
-
dy: numbers[3],
|
|
232
|
-
}));
|
|
233
|
-
}
|
|
234
|
-
if (command === 'T') {
|
|
235
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
236
|
-
type: command,
|
|
237
|
-
x: numbers[0],
|
|
238
|
-
y: numbers[1],
|
|
239
|
-
}));
|
|
240
|
-
}
|
|
241
|
-
if (command === 't') {
|
|
242
|
-
return makeInstructions(args, command, (numbers) => ({
|
|
243
|
-
type: command,
|
|
244
|
-
dx: numbers[0],
|
|
245
|
-
dy: numbers[1],
|
|
246
|
-
}));
|
|
247
|
-
}
|
|
248
|
-
throw new Error(`Invalid path element ${segmentString}`);
|
|
249
|
-
}, [])
|
|
250
|
-
.flat(1);
|
|
251
|
-
};
|
|
252
|
-
exports.parsePath = parsePath;
|
|
253
|
-
const parseValues = (args, instructionType) => {
|
|
254
|
-
const numbers = args.match(numberRegExp);
|
|
255
|
-
if (!numbers) {
|
|
256
|
-
if (instructionType === 'Z' || instructionType === 'z') {
|
|
257
|
-
return [];
|
|
258
|
-
}
|
|
259
|
-
throw new Error(`Malformed path data: ${instructionType} was expected to have numbers afterwards`);
|
|
260
|
-
}
|
|
261
|
-
const expectedArguments = length[instructionType];
|
|
262
|
-
if (numbers.length % expectedArguments !== 0) {
|
|
263
|
-
throw new Error(`Malformed path data: ${instructionType} was expected to have a multiple of ${expectedArguments} numbers, but got "${instructionType} ${numbers.join(' ')} instead"`);
|
|
264
|
-
}
|
|
265
|
-
return numbers.map(Number);
|
|
266
|
-
};
|
package/dist/serialize.d.ts
DELETED
package/dist/serialize.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.serializeInstructions = void 0;
|
|
4
|
-
const serializeInstruction = (instruction) => {
|
|
5
|
-
if (instruction.type === 'A') {
|
|
6
|
-
return `A ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.x} ${instruction.y}`;
|
|
7
|
-
}
|
|
8
|
-
if (instruction.type === 'a') {
|
|
9
|
-
return `a ${instruction.rx} ${instruction.ry} ${instruction.xAxisRotation} ${Number(instruction.largeArcFlag)} ${Number(instruction.sweepFlag)} ${instruction.dx} ${instruction.dy}`;
|
|
10
|
-
}
|
|
11
|
-
if (instruction.type === 'C') {
|
|
12
|
-
return `C ${instruction.cp1x} ${instruction.cp1y} ${instruction.cp2x} ${instruction.cp2y} ${instruction.x} ${instruction.y}`;
|
|
13
|
-
}
|
|
14
|
-
if (instruction.type === 'c') {
|
|
15
|
-
return `c ${instruction.cp1dx} ${instruction.cp1dy} ${instruction.cp2dx} ${instruction.cp2dy} ${instruction.dx} ${instruction.dy}`;
|
|
16
|
-
}
|
|
17
|
-
if (instruction.type === 'S') {
|
|
18
|
-
return `S ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
|
|
19
|
-
}
|
|
20
|
-
if (instruction.type === 's') {
|
|
21
|
-
return `s ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
|
|
22
|
-
}
|
|
23
|
-
if (instruction.type === 'Q') {
|
|
24
|
-
return `Q ${instruction.cpx} ${instruction.cpy} ${instruction.x} ${instruction.y}`;
|
|
25
|
-
}
|
|
26
|
-
if (instruction.type === 'q') {
|
|
27
|
-
return `q ${instruction.cpdx} ${instruction.cpdy} ${instruction.dx} ${instruction.dy}`;
|
|
28
|
-
}
|
|
29
|
-
if (instruction.type === 'z') {
|
|
30
|
-
return 'z';
|
|
31
|
-
}
|
|
32
|
-
if (instruction.type === 'Z') {
|
|
33
|
-
return 'Z';
|
|
34
|
-
}
|
|
35
|
-
if (instruction.type === 'H') {
|
|
36
|
-
return `H ${instruction.x}`;
|
|
37
|
-
}
|
|
38
|
-
if (instruction.type === 'h') {
|
|
39
|
-
return `h ${instruction.dx}`;
|
|
40
|
-
}
|
|
41
|
-
if (instruction.type === 'V') {
|
|
42
|
-
return `V ${instruction.y}`;
|
|
43
|
-
}
|
|
44
|
-
if (instruction.type === 'v') {
|
|
45
|
-
return `v ${instruction.dy}`;
|
|
46
|
-
}
|
|
47
|
-
if (instruction.type === 'L') {
|
|
48
|
-
return `L ${instruction.x} ${instruction.y}`;
|
|
49
|
-
}
|
|
50
|
-
if (instruction.type === 'l') {
|
|
51
|
-
return `l ${instruction.dx} ${instruction.dy}`;
|
|
52
|
-
}
|
|
53
|
-
if (instruction.type === 'M') {
|
|
54
|
-
return `M ${instruction.x} ${instruction.y}`;
|
|
55
|
-
}
|
|
56
|
-
if (instruction.type === 'm') {
|
|
57
|
-
return `m ${instruction.dx} ${instruction.dy}`;
|
|
58
|
-
}
|
|
59
|
-
if (instruction.type === 'T') {
|
|
60
|
-
return `T ${instruction.x} ${instruction.y}`;
|
|
61
|
-
}
|
|
62
|
-
if (instruction.type === 't') {
|
|
63
|
-
return `t ${instruction.dx} ${instruction.dy}`;
|
|
64
|
-
}
|
|
65
|
-
// @ts-expect-error
|
|
66
|
-
throw new Error(`Unknown instruction type: ${instruction.type}`);
|
|
67
|
-
};
|
|
68
|
-
const serializeInstructions = (path) => {
|
|
69
|
-
return path
|
|
70
|
-
.map((p) => {
|
|
71
|
-
return serializeInstruction(p);
|
|
72
|
-
})
|
|
73
|
-
.join(' ');
|
|
74
|
-
};
|
|
75
|
-
exports.serializeInstructions = serializeInstructions;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.reduceInstructions = void 0;
|
|
4
|
-
const remove_a_s_t_curves_1 = require("./helpers/remove-a-s-t-curves");
|
|
5
|
-
const normalize_path_1 = require("./normalize-path");
|
|
6
|
-
const reduceInstructions = (instruction) => {
|
|
7
|
-
const simplified = (0, normalize_path_1.normalizeInstructions)(instruction);
|
|
8
|
-
return (0, remove_a_s_t_curves_1.removeATSHVInstructions)(simplified);
|
|
9
|
-
};
|
|
10
|
-
exports.reduceInstructions = reduceInstructions;
|
package/dist/unarc.d.ts
DELETED
package/dist/unarc.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unarc = void 0;
|
|
4
|
-
const iterate_1 = require("./helpers/iterate");
|
|
5
|
-
const parse_1 = require("./helpers/parse");
|
|
6
|
-
const TAU = Math.PI * 2;
|
|
7
|
-
function approximate_unit_arc(theta1, delta_theta) {
|
|
8
|
-
const alpha = (4 / 3) * Math.tan(delta_theta / 4);
|
|
9
|
-
const x1 = Math.cos(theta1);
|
|
10
|
-
const y1 = Math.sin(theta1);
|
|
11
|
-
const x2 = Math.cos(theta1 + delta_theta);
|
|
12
|
-
const y2 = Math.sin(theta1 + delta_theta);
|
|
13
|
-
return [
|
|
14
|
-
x1,
|
|
15
|
-
y1,
|
|
16
|
-
x1 - y1 * alpha,
|
|
17
|
-
y1 + x1 * alpha,
|
|
18
|
-
x2 + y2 * alpha,
|
|
19
|
-
y2 - x2 * alpha,
|
|
20
|
-
x2,
|
|
21
|
-
y2,
|
|
22
|
-
];
|
|
23
|
-
}
|
|
24
|
-
function a2c({ x1, y1, x2, y2, fa, fs, rx, ry, phi, }) {
|
|
25
|
-
const sin_phi = Math.sin((phi * TAU) / 360);
|
|
26
|
-
const cos_phi = Math.cos((phi * TAU) / 360);
|
|
27
|
-
// Make sure radii are valid
|
|
28
|
-
//
|
|
29
|
-
const x1p = (cos_phi * (x1 - x2)) / 2 + (sin_phi * (y1 - y2)) / 2;
|
|
30
|
-
const y1p = (-sin_phi * (x1 - x2)) / 2 + (cos_phi * (y1 - y2)) / 2;
|
|
31
|
-
if (x1p === 0 && y1p === 0) {
|
|
32
|
-
// we're asked to draw line to itself
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
if (rx === 0 || ry === 0) {
|
|
36
|
-
// one of the radii is zero
|
|
37
|
-
return [];
|
|
38
|
-
}
|
|
39
|
-
// Compensate out-of-range radii
|
|
40
|
-
//
|
|
41
|
-
rx = Math.abs(rx);
|
|
42
|
-
ry = Math.abs(ry);
|
|
43
|
-
const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
|
|
44
|
-
if (lambda > 1) {
|
|
45
|
-
rx *= Math.sqrt(lambda);
|
|
46
|
-
ry *= Math.sqrt(lambda);
|
|
47
|
-
}
|
|
48
|
-
// Get center parameters (cx, cy, theta1, delta_theta)
|
|
49
|
-
//
|
|
50
|
-
const cc = get_arc_center({ x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi });
|
|
51
|
-
const result = [];
|
|
52
|
-
let theta1 = cc[2];
|
|
53
|
-
let delta_theta = cc[3];
|
|
54
|
-
// Split an arc to multiple segments, so each segment
|
|
55
|
-
// will be less than τ/4 (= 90°)
|
|
56
|
-
//
|
|
57
|
-
const segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
|
|
58
|
-
delta_theta /= segments;
|
|
59
|
-
for (let i = 0; i < segments; i++) {
|
|
60
|
-
result.push(approximate_unit_arc(theta1, delta_theta));
|
|
61
|
-
theta1 += delta_theta;
|
|
62
|
-
}
|
|
63
|
-
// We have a bezier approximation of a unit circle,
|
|
64
|
-
// now need to transform back to the original ellipse
|
|
65
|
-
//
|
|
66
|
-
return result.map((curve) => {
|
|
67
|
-
for (let i = 0; i < curve.length; i += 2) {
|
|
68
|
-
let x = curve[i + 0];
|
|
69
|
-
let y = curve[i + 1];
|
|
70
|
-
// scale
|
|
71
|
-
x *= rx;
|
|
72
|
-
y *= ry;
|
|
73
|
-
// rotate
|
|
74
|
-
const xp = cos_phi * x - sin_phi * y;
|
|
75
|
-
const yp = sin_phi * x + cos_phi * y;
|
|
76
|
-
// translate
|
|
77
|
-
curve[i + 0] = xp + cc[0];
|
|
78
|
-
curve[i + 1] = yp + cc[1];
|
|
79
|
-
}
|
|
80
|
-
return curve;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
// Requires path to be normalized
|
|
84
|
-
const unarc = (d) => {
|
|
85
|
-
const segments = (0, parse_1.parsePath)(d);
|
|
86
|
-
const x = 0;
|
|
87
|
-
const y = 0;
|
|
88
|
-
return (0, iterate_1.iterateOverSegments)(segments, ({ segment }) => {
|
|
89
|
-
const nextX = segment[6];
|
|
90
|
-
const nextY = segment[7];
|
|
91
|
-
const new_segments = a2c({
|
|
92
|
-
x1: x,
|
|
93
|
-
y1: y,
|
|
94
|
-
x2: nextX,
|
|
95
|
-
y2: nextY,
|
|
96
|
-
fa: segment[4],
|
|
97
|
-
fs: segment[5],
|
|
98
|
-
rx: segment[1],
|
|
99
|
-
ry: segment[2],
|
|
100
|
-
phi: segment[3],
|
|
101
|
-
});
|
|
102
|
-
// Degenerated arcs can be ignored by renderer, but should not be dropped
|
|
103
|
-
// to avoid collisions with `S A S` and so on. Replace with empty line.
|
|
104
|
-
if (new_segments.length === 0) {
|
|
105
|
-
return [['L', segment[6], segment[7]]];
|
|
106
|
-
}
|
|
107
|
-
const result = [];
|
|
108
|
-
new_segments.forEach((_s) => {
|
|
109
|
-
result.push(['C', _s[2], _s[3], _s[4], _s[5], _s[6], _s[7]]);
|
|
110
|
-
});
|
|
111
|
-
return result;
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
exports.unarc = unarc;
|
|
115
|
-
function get_arc_center({ x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi, }) {
|
|
116
|
-
// Step 1.
|
|
117
|
-
//
|
|
118
|
-
// Moving an ellipse so origin will be the middlepoint between our two
|
|
119
|
-
// points. After that, rotate it to line up ellipse axes with coordinate
|
|
120
|
-
// axes.
|
|
121
|
-
//
|
|
122
|
-
const x1p = (cos_phi * (x1 - x2)) / 2 + (sin_phi * (y1 - y2)) / 2;
|
|
123
|
-
const y1p = (-sin_phi * (x1 - x2)) / 2 + (cos_phi * (y1 - y2)) / 2;
|
|
124
|
-
const rx_sq = rx * rx;
|
|
125
|
-
const ry_sq = ry * ry;
|
|
126
|
-
const x1p_sq = x1p * x1p;
|
|
127
|
-
const y1p_sq = y1p * y1p;
|
|
128
|
-
// Step 2.
|
|
129
|
-
//
|
|
130
|
-
// Compute coordinates of the centre of this ellipse (cx', cy')
|
|
131
|
-
// in the new coordinate system.
|
|
132
|
-
//
|
|
133
|
-
let radicant = rx_sq * ry_sq - rx_sq * y1p_sq - ry_sq * x1p_sq;
|
|
134
|
-
if (radicant < 0) {
|
|
135
|
-
// due to rounding errors it might be e.g. -1.3877787807814457e-17
|
|
136
|
-
radicant = 0;
|
|
137
|
-
}
|
|
138
|
-
radicant /= rx_sq * y1p_sq + ry_sq * x1p_sq;
|
|
139
|
-
radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
|
|
140
|
-
const cxp = ((radicant * rx) / ry) * y1p;
|
|
141
|
-
const cyp = ((radicant * -ry) / rx) * x1p;
|
|
142
|
-
// Step 3.
|
|
143
|
-
//
|
|
144
|
-
// Transform back to get centre coordinates (cx, cy) in the original
|
|
145
|
-
// coordinate system.
|
|
146
|
-
//
|
|
147
|
-
const cx = cos_phi * cxp - sin_phi * cyp + (x1 + x2) / 2;
|
|
148
|
-
const cy = sin_phi * cxp + cos_phi * cyp + (y1 + y2) / 2;
|
|
149
|
-
// Step 4.
|
|
150
|
-
//
|
|
151
|
-
// Compute angles (theta1, delta_theta).
|
|
152
|
-
//
|
|
153
|
-
const v1x = (x1p - cxp) / rx;
|
|
154
|
-
const v1y = (y1p - cyp) / ry;
|
|
155
|
-
const v2x = (-x1p - cxp) / rx;
|
|
156
|
-
const v2y = (-y1p - cyp) / ry;
|
|
157
|
-
const theta1 = unit_vector_angle(1, 0, v1x, v1y);
|
|
158
|
-
let delta_theta = unit_vector_angle(v1x, v1y, v2x, v2y);
|
|
159
|
-
if (fs === 0 && delta_theta > 0) {
|
|
160
|
-
delta_theta -= TAU;
|
|
161
|
-
}
|
|
162
|
-
if (fs === 1 && delta_theta < 0) {
|
|
163
|
-
delta_theta += TAU;
|
|
164
|
-
}
|
|
165
|
-
return [cx, cy, theta1, delta_theta];
|
|
166
|
-
}
|
|
167
|
-
function unit_vector_angle(ux, uy, vx, vy) {
|
|
168
|
-
const sign = ux * vy - uy * vx < 0 ? -1 : 1;
|
|
169
|
-
let dot = ux * vx + uy * vy;
|
|
170
|
-
// Add this to work with arbitrary vectors:
|
|
171
|
-
// dot /= Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
|
|
172
|
-
// rounding errors, e.g. -1.0000000000000002 can screw up this
|
|
173
|
-
if (dot > 1.0) {
|
|
174
|
-
dot = 1.0;
|
|
175
|
-
}
|
|
176
|
-
if (dot < -1.0) {
|
|
177
|
-
dot = -1.0;
|
|
178
|
-
}
|
|
179
|
-
return sign * Math.acos(dot);
|
|
180
|
-
}
|
package/dist/unshort.d.ts
DELETED
package/dist/unshort.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unshort = void 0;
|
|
4
|
-
// Requires that the path is already normalized
|
|
5
|
-
const unshort = function (segments) {
|
|
6
|
-
let prevControlX = 0;
|
|
7
|
-
let prevControlY = 0;
|
|
8
|
-
let curControlX = 0;
|
|
9
|
-
let curControlY = 0;
|
|
10
|
-
let x = 0;
|
|
11
|
-
let y = 0;
|
|
12
|
-
const newSegments = segments.slice(0);
|
|
13
|
-
for (let i = 0; i < newSegments.length; i++) {
|
|
14
|
-
const s = newSegments[i];
|
|
15
|
-
const name = s[0];
|
|
16
|
-
switch (s[0]) {
|
|
17
|
-
case 'M':
|
|
18
|
-
case 'L': {
|
|
19
|
-
x = s[1];
|
|
20
|
-
y = s[2];
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
case 'V': {
|
|
24
|
-
y = s[1];
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
case 'H': {
|
|
28
|
-
x = s[1];
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
case 'C': {
|
|
32
|
-
x = s[5];
|
|
33
|
-
y = s[6];
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
case 'Q': {
|
|
37
|
-
x = s[3];
|
|
38
|
-
y = s[4];
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
case 'Z':
|
|
42
|
-
break;
|
|
43
|
-
default:
|
|
44
|
-
throw new Error('Unexpected command: ' + s[0]);
|
|
45
|
-
}
|
|
46
|
-
const nameUC = name.toUpperCase();
|
|
47
|
-
let isRelative;
|
|
48
|
-
// First command MUST be M|m, it's safe to skip.
|
|
49
|
-
// Protect from access to [-1] for sure.
|
|
50
|
-
if (!i) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
if (nameUC === 'T') {
|
|
54
|
-
// quadratic curve
|
|
55
|
-
isRelative = name === 't';
|
|
56
|
-
const prevSegment = newSegments[i - 1];
|
|
57
|
-
if (prevSegment[0] === 'Q') {
|
|
58
|
-
prevControlX = prevSegment[1] - x;
|
|
59
|
-
prevControlY = prevSegment[2] - y;
|
|
60
|
-
}
|
|
61
|
-
else if (prevSegment[0] === 'q') {
|
|
62
|
-
prevControlX = prevSegment[1] - prevSegment[3];
|
|
63
|
-
prevControlY = prevSegment[2] - prevSegment[4];
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
prevControlX = 0;
|
|
67
|
-
prevControlY = 0;
|
|
68
|
-
}
|
|
69
|
-
curControlX = -prevControlX;
|
|
70
|
-
curControlY = -prevControlY;
|
|
71
|
-
if (!isRelative) {
|
|
72
|
-
curControlX += x;
|
|
73
|
-
curControlY += y;
|
|
74
|
-
}
|
|
75
|
-
newSegments[i] = [
|
|
76
|
-
isRelative ? 'q' : 'Q',
|
|
77
|
-
curControlX,
|
|
78
|
-
curControlY,
|
|
79
|
-
s[1],
|
|
80
|
-
s[2],
|
|
81
|
-
];
|
|
82
|
-
}
|
|
83
|
-
else if (nameUC === 'S') {
|
|
84
|
-
// cubic curve
|
|
85
|
-
isRelative = name === 's';
|
|
86
|
-
const prevSegment = newSegments[i - 1];
|
|
87
|
-
if (prevSegment[0] === 'C') {
|
|
88
|
-
prevControlX = prevSegment[3] - x;
|
|
89
|
-
prevControlY = prevSegment[4] - y;
|
|
90
|
-
}
|
|
91
|
-
else if (prevSegment[0] === 'c') {
|
|
92
|
-
prevControlX = prevSegment[3] - prevSegment[5];
|
|
93
|
-
prevControlY = prevSegment[4] - prevSegment[6];
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
prevControlX = 0;
|
|
97
|
-
prevControlY = 0;
|
|
98
|
-
}
|
|
99
|
-
curControlX = -prevControlX;
|
|
100
|
-
curControlY = -prevControlY;
|
|
101
|
-
if (!isRelative) {
|
|
102
|
-
curControlX += x;
|
|
103
|
-
curControlY += y;
|
|
104
|
-
}
|
|
105
|
-
newSegments[i] = [
|
|
106
|
-
isRelative ? 'c' : 'C',
|
|
107
|
-
curControlX,
|
|
108
|
-
curControlY,
|
|
109
|
-
s[1],
|
|
110
|
-
s[2],
|
|
111
|
-
s[3],
|
|
112
|
-
s[4],
|
|
113
|
-
];
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return newSegments;
|
|
117
|
-
};
|
|
118
|
-
exports.unshort = unshort;
|