svg-path-commander 2.1.2 → 2.1.5
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/README.md +4 -4
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +755 -849
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +947 -611
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +14 -22
- package/.eslintrc.cjs +0 -225
- package/.prettierrc.json +0 -15
- package/dts.config.ts +0 -15
- package/src/convert/pathToAbsolute.ts +0 -18
- package/src/convert/pathToCurve.ts +0 -43
- package/src/convert/pathToRelative.ts +0 -18
- package/src/convert/pathToString.ts +0 -50
- package/src/index.ts +0 -454
- package/src/interface.ts +0 -130
- package/src/math/arcTools.ts +0 -396
- package/src/math/bezier.ts +0 -261
- package/src/math/cubicTools.ts +0 -124
- package/src/math/distanceSquareRoot.ts +0 -15
- package/src/math/lineTools.ts +0 -69
- package/src/math/midPoint.ts +0 -18
- package/src/math/polygonTools.ts +0 -48
- package/src/math/quadTools.ts +0 -100
- package/src/math/rotateVector.ts +0 -17
- package/src/math/roundTo.ts +0 -7
- package/src/options/options.ts +0 -9
- package/src/parser/error.ts +0 -2
- package/src/parser/finalizeSegment.ts +0 -35
- package/src/parser/invalidPathValue.ts +0 -2
- package/src/parser/isArcCommand.ts +0 -11
- package/src/parser/isDigit.ts +0 -12
- package/src/parser/isDigitStart.ts +0 -14
- package/src/parser/isMoveCommand.ts +0 -17
- package/src/parser/isPathCommand.ts +0 -28
- package/src/parser/isSpace.ts +0 -23
- package/src/parser/paramsCount.ts +0 -16
- package/src/parser/paramsParser.ts +0 -14
- package/src/parser/parsePathString.ts +0 -33
- package/src/parser/pathParser.ts +0 -29
- package/src/parser/scanFlag.ts +0 -29
- package/src/parser/scanParam.ts +0 -102
- package/src/parser/scanSegment.ts +0 -84
- package/src/parser/skipSpaces.ts +0 -17
- package/src/process/absolutizeSegment.ts +0 -63
- package/src/process/arcToCubic.ts +0 -128
- package/src/process/getSVGMatrix.ts +0 -70
- package/src/process/iterate.ts +0 -58
- package/src/process/lineToCubic.ts +0 -17
- package/src/process/normalizePath.ts +0 -33
- package/src/process/normalizeSegment.ts +0 -84
- package/src/process/optimizePath.ts +0 -63
- package/src/process/projection2d.ts +0 -52
- package/src/process/quadToCubic.ts +0 -31
- package/src/process/relativizeSegment.ts +0 -59
- package/src/process/reverseCurve.ts +0 -24
- package/src/process/reversePath.ts +0 -114
- package/src/process/roundPath.ts +0 -33
- package/src/process/roundSegment.ts +0 -9
- package/src/process/segmentToCubic.ts +0 -48
- package/src/process/shortenSegment.ts +0 -71
- package/src/process/splitCubic.ts +0 -29
- package/src/process/splitPath.ts +0 -63
- package/src/process/transformPath.ts +0 -110
- package/src/types.ts +0 -228
- package/src/util/distanceEpsilon.ts +0 -3
- package/src/util/getClosestPoint.ts +0 -15
- package/src/util/getDrawDirection.ts +0 -16
- package/src/util/getPathArea.ts +0 -70
- package/src/util/getPathBBox.ts +0 -98
- package/src/util/getPointAtLength.ts +0 -110
- package/src/util/getPropertiesAtLength.ts +0 -67
- package/src/util/getPropertiesAtPoint.ts +0 -84
- package/src/util/getSegmentAtLength.ts +0 -15
- package/src/util/getSegmentOfPoint.ts +0 -18
- package/src/util/getTotalLength.ts +0 -68
- package/src/util/isAbsoluteArray.ts +0 -18
- package/src/util/isCurveArray.ts +0 -15
- package/src/util/isNormalizedArray.ts +0 -16
- package/src/util/isPathArray.ts +0 -24
- package/src/util/isPointInStroke.ts +0 -16
- package/src/util/isRelativeArray.ts +0 -18
- package/src/util/isValidPath.ts +0 -27
- package/src/util/shapeParams.ts +0 -16
- package/src/util/shapeToPath.ts +0 -86
- package/src/util/shapeToPathArray.ts +0 -183
- package/test/class.test.ts +0 -504
- package/test/fixtures/getMarkup.ts +0 -17
- package/test/fixtures/shapeObjects.ts +0 -11
- package/test/fixtures/shapes.js +0 -104
- package/test/fixtures/simpleShapes.js +0 -75
- package/test/static.test.ts +0 -330
- package/vite.config.mts +0 -41
- package/vitest.config-ui.mts +0 -26
- package/vitest.config.mts +0 -26
package/src/math/arcTools.ts
DELETED
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
import { getPointAtLineLength } from './lineTools';
|
|
2
|
-
import type { Point } from '../types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Returns the Arc segment length.
|
|
6
|
-
* @param rx radius along X axis
|
|
7
|
-
* @param ry radius along Y axis
|
|
8
|
-
* @param theta the angle in radians
|
|
9
|
-
* @returns the arc length
|
|
10
|
-
*/
|
|
11
|
-
const arcLength = (rx: number, ry: number, theta: number) => {
|
|
12
|
-
const halfTheta = theta / 2;
|
|
13
|
-
const sinHalfTheta = Math.sin(halfTheta);
|
|
14
|
-
const cosHalfTheta = Math.cos(halfTheta);
|
|
15
|
-
const term1 = rx ** 2 * sinHalfTheta ** 2;
|
|
16
|
-
const term2 = ry ** 2 * cosHalfTheta ** 2;
|
|
17
|
-
const length = Math.sqrt(term1 + term2) * theta;
|
|
18
|
-
return Math.abs(length);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Find point on ellipse at given angle around ellipse (theta);
|
|
23
|
-
* @param cx the center X
|
|
24
|
-
* @param cy the center Y
|
|
25
|
-
* @param rx the radius X
|
|
26
|
-
* @param ry the radius Y
|
|
27
|
-
* @param alpha the arc rotation angle in radians
|
|
28
|
-
* @param theta the arc sweep angle in radians
|
|
29
|
-
* @returns a point around ellipse at given angle
|
|
30
|
-
*/
|
|
31
|
-
const arcPoint = (cx: number, cy: number, rx: number, ry: number, alpha: number, theta: number) => {
|
|
32
|
-
const { sin, cos } = Math;
|
|
33
|
-
// theta is angle in radians around arc
|
|
34
|
-
// alpha is angle of rotation of ellipse in radians
|
|
35
|
-
const cosA = cos(alpha);
|
|
36
|
-
const sinA = sin(alpha);
|
|
37
|
-
const x = rx * cos(theta);
|
|
38
|
-
const y = ry * sin(theta);
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
x: cx + cosA * x - sinA * y,
|
|
42
|
-
y: cy + sinA * x + cosA * y,
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Returns the angle between two points.
|
|
48
|
-
* @param v0 starting point
|
|
49
|
-
* @param v1 ending point
|
|
50
|
-
* @returns the angle in radian
|
|
51
|
-
*/
|
|
52
|
-
const angleBetween = (v0: Point, v1: Point) => {
|
|
53
|
-
const { x: v0x, y: v0y } = v0;
|
|
54
|
-
const { x: v1x, y: v1y } = v1;
|
|
55
|
-
const p = v0x * v1x + v0y * v1y;
|
|
56
|
-
const n = Math.sqrt((v0x ** 2 + v0y ** 2) * (v1x ** 2 + v1y ** 2));
|
|
57
|
-
const sign = v0x * v1y - v0y * v1x < 0 ? -1 : 1;
|
|
58
|
-
return sign * Math.acos(p / n);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Returns the following properties for an Arc segment: center, start angle,
|
|
63
|
-
* end angle, and radiuses on X and Y axis.
|
|
64
|
-
*
|
|
65
|
-
* @param x1 the starting point X
|
|
66
|
-
* @param y1 the starting point Y
|
|
67
|
-
* @param RX the radius on X axis
|
|
68
|
-
* @param RY the radius on Y axis
|
|
69
|
-
* @param angle the ellipse rotation in degrees
|
|
70
|
-
* @param LAF the large arc flag
|
|
71
|
-
* @param SF the sweep flag
|
|
72
|
-
* @param x2 the ending point X
|
|
73
|
-
* @param y2 the ending point Y
|
|
74
|
-
* @returns properties specific to Arc segments
|
|
75
|
-
*/
|
|
76
|
-
const getArcProps = (
|
|
77
|
-
x1: number,
|
|
78
|
-
y1: number,
|
|
79
|
-
RX: number,
|
|
80
|
-
RY: number,
|
|
81
|
-
angle: number,
|
|
82
|
-
LAF: number,
|
|
83
|
-
SF: number,
|
|
84
|
-
x: number,
|
|
85
|
-
y: number,
|
|
86
|
-
) => {
|
|
87
|
-
const { abs, sin, cos, sqrt, PI } = Math;
|
|
88
|
-
let rx = abs(RX);
|
|
89
|
-
let ry = abs(RY);
|
|
90
|
-
const xRot = ((angle % 360) + 360) % 360;
|
|
91
|
-
const xRotRad = xRot * (PI / 180);
|
|
92
|
-
|
|
93
|
-
// istanbul ignore next @preserve
|
|
94
|
-
if (x1 === x && y1 === y) {
|
|
95
|
-
return {
|
|
96
|
-
rx,
|
|
97
|
-
ry,
|
|
98
|
-
startAngle: 0,
|
|
99
|
-
endAngle: 0,
|
|
100
|
-
center: { x, y },
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (rx === 0 || ry === 0) {
|
|
105
|
-
return {
|
|
106
|
-
rx,
|
|
107
|
-
ry,
|
|
108
|
-
startAngle: 0,
|
|
109
|
-
endAngle: 0,
|
|
110
|
-
center: { x: (x + x1) / 2, y: (y + y1) / 2 },
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const dx = (x1 - x) / 2;
|
|
115
|
-
const dy = (y1 - y) / 2;
|
|
116
|
-
|
|
117
|
-
const transformedPoint = {
|
|
118
|
-
x: cos(xRotRad) * dx + sin(xRotRad) * dy,
|
|
119
|
-
y: -sin(xRotRad) * dx + cos(xRotRad) * dy,
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const radiiCheck = transformedPoint.x ** 2 / rx ** 2 + transformedPoint.y ** 2 / ry ** 2;
|
|
123
|
-
|
|
124
|
-
if (radiiCheck > 1) {
|
|
125
|
-
rx *= sqrt(radiiCheck);
|
|
126
|
-
ry *= sqrt(radiiCheck);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const cSquareNumerator = rx ** 2 * ry ** 2 - rx ** 2 * transformedPoint.y ** 2 - ry ** 2 * transformedPoint.x ** 2;
|
|
130
|
-
const cSquareRootDenom = rx ** 2 * transformedPoint.y ** 2 + ry ** 2 * transformedPoint.x ** 2;
|
|
131
|
-
|
|
132
|
-
let cRadicand = cSquareNumerator / cSquareRootDenom;
|
|
133
|
-
/* istanbul ignore next @preserve */
|
|
134
|
-
cRadicand = cRadicand < 0 ? 0 : cRadicand;
|
|
135
|
-
const cCoef = (LAF !== SF ? 1 : -1) * sqrt(cRadicand);
|
|
136
|
-
const transformedCenter = {
|
|
137
|
-
x: cCoef * ((rx * transformedPoint.y) / ry),
|
|
138
|
-
y: cCoef * (-(ry * transformedPoint.x) / rx),
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const center = {
|
|
142
|
-
x: cos(xRotRad) * transformedCenter.x - sin(xRotRad) * transformedCenter.y + (x1 + x) / 2,
|
|
143
|
-
y: sin(xRotRad) * transformedCenter.x + cos(xRotRad) * transformedCenter.y + (y1 + y) / 2,
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const startVector = {
|
|
147
|
-
x: (transformedPoint.x - transformedCenter.x) / rx,
|
|
148
|
-
y: (transformedPoint.y - transformedCenter.y) / ry,
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const startAngle = angleBetween({ x: 1, y: 0 }, startVector);
|
|
152
|
-
|
|
153
|
-
const endVector = {
|
|
154
|
-
x: (-transformedPoint.x - transformedCenter.x) / rx,
|
|
155
|
-
y: (-transformedPoint.y - transformedCenter.y) / ry,
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
let sweepAngle = angleBetween(startVector, endVector);
|
|
159
|
-
if (!SF && sweepAngle > 0) {
|
|
160
|
-
sweepAngle -= 2 * PI;
|
|
161
|
-
} else if (SF && sweepAngle < 0) {
|
|
162
|
-
sweepAngle += 2 * PI;
|
|
163
|
-
}
|
|
164
|
-
sweepAngle %= 2 * PI;
|
|
165
|
-
|
|
166
|
-
const endAngle = startAngle + sweepAngle;
|
|
167
|
-
|
|
168
|
-
// point.ellipticalArcStartAngle = startAngle;
|
|
169
|
-
// point.ellipticalArcEndAngle = startAngle + sweepAngle;
|
|
170
|
-
// point.ellipticalArcAngle = alpha;
|
|
171
|
-
|
|
172
|
-
// point.ellipticalArcCenter = center;
|
|
173
|
-
// point.resultantRx = rx;
|
|
174
|
-
// point.resultantRy = ry;
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
center,
|
|
178
|
-
startAngle,
|
|
179
|
-
endAngle,
|
|
180
|
-
rx,
|
|
181
|
-
ry,
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Returns the length of an Arc segment.
|
|
187
|
-
*
|
|
188
|
-
* @param x1 the starting point X
|
|
189
|
-
* @param y1 the starting point Y
|
|
190
|
-
* @param c1x the first control point X
|
|
191
|
-
* @param c1y the first control point Y
|
|
192
|
-
* @param c2x the second control point X
|
|
193
|
-
* @param c2y the second control point Y
|
|
194
|
-
* @param x2 the ending point X
|
|
195
|
-
* @param y2 the ending point Y
|
|
196
|
-
* @returns the length of the Arc segment
|
|
197
|
-
*/
|
|
198
|
-
const getArcLength = (
|
|
199
|
-
x1: number,
|
|
200
|
-
y1: number,
|
|
201
|
-
RX: number,
|
|
202
|
-
RY: number,
|
|
203
|
-
angle: number,
|
|
204
|
-
LAF: number,
|
|
205
|
-
SF: number,
|
|
206
|
-
x: number,
|
|
207
|
-
y: number,
|
|
208
|
-
) => {
|
|
209
|
-
const { rx, ry, startAngle, endAngle } = getArcProps(x1, y1, RX, RY, angle, LAF, SF, x, y);
|
|
210
|
-
return arcLength(rx, ry, endAngle - startAngle);
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Returns a point along an Arc segment at a given distance.
|
|
215
|
-
*
|
|
216
|
-
* @param x1 the starting point X
|
|
217
|
-
* @param y1 the starting point Y
|
|
218
|
-
* @param RX the radius on X axis
|
|
219
|
-
* @param RY the radius on Y axis
|
|
220
|
-
* @param angle the ellipse rotation in degrees
|
|
221
|
-
* @param LAF the large arc flag
|
|
222
|
-
* @param SF the sweep flag
|
|
223
|
-
* @param x2 the ending point X
|
|
224
|
-
* @param y2 the ending point Y
|
|
225
|
-
* @param distance a [0-1] ratio
|
|
226
|
-
* @returns a point along the Arc segment
|
|
227
|
-
*/
|
|
228
|
-
const getPointAtArcLength = (
|
|
229
|
-
x1: number,
|
|
230
|
-
y1: number,
|
|
231
|
-
RX: number,
|
|
232
|
-
RY: number,
|
|
233
|
-
angle: number,
|
|
234
|
-
LAF: number,
|
|
235
|
-
SF: number,
|
|
236
|
-
x: number,
|
|
237
|
-
y: number,
|
|
238
|
-
distance?: number,
|
|
239
|
-
) => {
|
|
240
|
-
let point = { x: x1, y: y1 };
|
|
241
|
-
const { center, rx, ry, startAngle, endAngle } = getArcProps(x1, y1, RX, RY, angle, LAF, SF, x, y);
|
|
242
|
-
|
|
243
|
-
/* istanbul ignore else @preserve */
|
|
244
|
-
if (typeof distance === 'number') {
|
|
245
|
-
const length = arcLength(rx, ry, endAngle - startAngle);
|
|
246
|
-
if (distance <= 0) {
|
|
247
|
-
point = { x: x1, y: y1 };
|
|
248
|
-
} else if (distance >= length) {
|
|
249
|
-
point = { x, y };
|
|
250
|
-
} else {
|
|
251
|
-
/* istanbul ignore next @preserve */
|
|
252
|
-
if (x1 === x && y1 === y) {
|
|
253
|
-
return { x, y };
|
|
254
|
-
}
|
|
255
|
-
/* istanbul ignore next @preserve */
|
|
256
|
-
if (rx === 0 || ry === 0) {
|
|
257
|
-
return getPointAtLineLength(x1, y1, x, y, distance);
|
|
258
|
-
}
|
|
259
|
-
const { PI, cos, sin } = Math;
|
|
260
|
-
const sweepAngle = endAngle - startAngle;
|
|
261
|
-
const xRot = ((angle % 360) + 360) % 360;
|
|
262
|
-
const xRotRad = xRot * (PI / 180);
|
|
263
|
-
const alpha = startAngle + sweepAngle * (distance / length);
|
|
264
|
-
const ellipseComponentX = rx * cos(alpha);
|
|
265
|
-
const ellipseComponentY = ry * sin(alpha);
|
|
266
|
-
|
|
267
|
-
point = {
|
|
268
|
-
x: cos(xRotRad) * ellipseComponentX - sin(xRotRad) * ellipseComponentY + center.x,
|
|
269
|
-
y: sin(xRotRad) * ellipseComponentX + cos(xRotRad) * ellipseComponentY + center.y,
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return point;
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Returns the extrema for an Arc segment.
|
|
279
|
-
* @see https://github.com/herrstrietzel/svg-pathdata-getbbox
|
|
280
|
-
*
|
|
281
|
-
* @param x1 the starting point X
|
|
282
|
-
* @param y1 the starting point Y
|
|
283
|
-
* @param RX the radius on X axis
|
|
284
|
-
* @param RY the radius on Y axis
|
|
285
|
-
* @param angle the ellipse rotation in degrees
|
|
286
|
-
* @param LAF the large arc flag
|
|
287
|
-
* @param SF the sweep flag
|
|
288
|
-
* @param x2 the ending point X
|
|
289
|
-
* @param y2 the ending point Y
|
|
290
|
-
* @returns the extrema of the Arc segment
|
|
291
|
-
*
|
|
292
|
-
*/
|
|
293
|
-
const getArcBBox = (
|
|
294
|
-
x1: number,
|
|
295
|
-
y1: number,
|
|
296
|
-
RX: number,
|
|
297
|
-
RY: number,
|
|
298
|
-
angle: number,
|
|
299
|
-
LAF: number,
|
|
300
|
-
SF: number,
|
|
301
|
-
x: number,
|
|
302
|
-
y: number,
|
|
303
|
-
) => {
|
|
304
|
-
const { center, rx, ry, startAngle, endAngle } = getArcProps(x1, y1, RX, RY, angle, LAF, SF, x, y);
|
|
305
|
-
const deltaAngle = endAngle - startAngle;
|
|
306
|
-
const { min, max, tan, atan2, PI } = Math;
|
|
307
|
-
|
|
308
|
-
// final on path point
|
|
309
|
-
const p = { x, y };
|
|
310
|
-
|
|
311
|
-
// circle/elipse center coordinates
|
|
312
|
-
const { x: cx, y: cy } = center;
|
|
313
|
-
|
|
314
|
-
// collect extreme points – add end point
|
|
315
|
-
const extremes = [p];
|
|
316
|
-
|
|
317
|
-
// rotation to radians
|
|
318
|
-
const alpha = (angle * PI) / 180;
|
|
319
|
-
const tangent = tan(alpha);
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* find min/max from zeroes of directional derivative along x and y
|
|
323
|
-
* along x axis
|
|
324
|
-
*/
|
|
325
|
-
const theta = atan2(-ry * tangent, rx);
|
|
326
|
-
const angle1 = theta;
|
|
327
|
-
const angle2 = theta + PI;
|
|
328
|
-
const angle3 = atan2(ry, rx * tangent);
|
|
329
|
-
const angle4 = angle3 + PI;
|
|
330
|
-
|
|
331
|
-
// inner bounding box
|
|
332
|
-
const xArr = [x1, x];
|
|
333
|
-
const yArr = [y1, y];
|
|
334
|
-
const xMin = min(...xArr);
|
|
335
|
-
const xMax = max(...xArr);
|
|
336
|
-
const yMin = min(...yArr);
|
|
337
|
-
const yMax = max(...yArr);
|
|
338
|
-
|
|
339
|
-
// on path point close after start
|
|
340
|
-
const angleAfterStart = endAngle - deltaAngle * 0.001;
|
|
341
|
-
const pP2 = arcPoint(cx, cy, rx, ry, alpha, angleAfterStart);
|
|
342
|
-
|
|
343
|
-
// on path point close before end
|
|
344
|
-
const angleBeforeEnd = endAngle - deltaAngle * 0.999;
|
|
345
|
-
const pP3 = arcPoint(cx, cy, rx, ry, alpha, angleBeforeEnd);
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* expected extremes
|
|
349
|
-
* if leaving inner bounding box
|
|
350
|
-
* (between segment start and end point)
|
|
351
|
-
* otherwise exclude elliptic extreme points
|
|
352
|
-
*/
|
|
353
|
-
|
|
354
|
-
// right
|
|
355
|
-
// istanbul ignore if @preserve
|
|
356
|
-
if (pP2.x > xMax || pP3.x > xMax) {
|
|
357
|
-
// get point for this theta
|
|
358
|
-
extremes.push(arcPoint(cx, cy, rx, ry, alpha, angle1));
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// left
|
|
362
|
-
// istanbul ignore if @preserve
|
|
363
|
-
if (pP2.x < xMin || pP3.x < xMin) {
|
|
364
|
-
// get anti-symmetric point
|
|
365
|
-
extremes.push(arcPoint(cx, cy, rx, ry, alpha, angle2));
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// top
|
|
369
|
-
// istanbul ignore if @preserve
|
|
370
|
-
if (pP2.y < yMin || pP3.y < yMin) {
|
|
371
|
-
// get anti-symmetric point
|
|
372
|
-
extremes.push(arcPoint(cx, cy, rx, ry, alpha, angle4));
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// bottom
|
|
376
|
-
// istanbul ignore if @preserve
|
|
377
|
-
if (pP2.y > yMax || pP3.y > yMax) {
|
|
378
|
-
// get point for this theta
|
|
379
|
-
extremes.push(arcPoint(cx, cy, rx, ry, alpha, angle3));
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
return {
|
|
383
|
-
min: {
|
|
384
|
-
x: min(...extremes.map(n => n.x)),
|
|
385
|
-
y: min(...extremes.map(n => n.y)),
|
|
386
|
-
},
|
|
387
|
-
max: {
|
|
388
|
-
x: max(...extremes.map(n => n.x)),
|
|
389
|
-
y: max(...extremes.map(n => n.y)),
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
export { arcPoint, angleBetween, getArcLength, arcLength, getArcBBox, getArcProps, getPointAtArcLength };
|
|
395
|
-
|
|
396
|
-
export {};
|
package/src/math/bezier.ts
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PointTuple,
|
|
3
|
-
DerivedPoint,
|
|
4
|
-
QuadPoints,
|
|
5
|
-
CubicPoints,
|
|
6
|
-
DerivedQuadPoints,
|
|
7
|
-
DerivedCubicPoints,
|
|
8
|
-
QuadCoordinates,
|
|
9
|
-
CubicCoordinates,
|
|
10
|
-
DeriveCallback,
|
|
11
|
-
} from '../types';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Tools from bezier.js by Mike 'Pomax' Kamermans
|
|
15
|
-
* @see https://github.com/Pomax/bezierjs
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const Tvalues = [
|
|
19
|
-
-0.0640568928626056260850430826247450385909, 0.0640568928626056260850430826247450385909,
|
|
20
|
-
-0.1911188674736163091586398207570696318404, 0.1911188674736163091586398207570696318404,
|
|
21
|
-
-0.3150426796961633743867932913198102407864, 0.3150426796961633743867932913198102407864,
|
|
22
|
-
-0.4337935076260451384870842319133497124524, 0.4337935076260451384870842319133497124524,
|
|
23
|
-
-0.5454214713888395356583756172183723700107, 0.5454214713888395356583756172183723700107,
|
|
24
|
-
-0.6480936519369755692524957869107476266696, 0.6480936519369755692524957869107476266696,
|
|
25
|
-
-0.7401241915785543642438281030999784255232, 0.7401241915785543642438281030999784255232,
|
|
26
|
-
-0.8200019859739029219539498726697452080761, 0.8200019859739029219539498726697452080761,
|
|
27
|
-
-0.8864155270044010342131543419821967550873, 0.8864155270044010342131543419821967550873,
|
|
28
|
-
-0.9382745520027327585236490017087214496548, 0.9382745520027327585236490017087214496548,
|
|
29
|
-
-0.9747285559713094981983919930081690617411, 0.9747285559713094981983919930081690617411,
|
|
30
|
-
-0.9951872199970213601799974097007368118745, 0.9951872199970213601799974097007368118745,
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const Cvalues = [
|
|
34
|
-
0.1279381953467521569740561652246953718517, 0.1279381953467521569740561652246953718517,
|
|
35
|
-
0.1258374563468282961213753825111836887264, 0.1258374563468282961213753825111836887264,
|
|
36
|
-
0.121670472927803391204463153476262425607, 0.121670472927803391204463153476262425607,
|
|
37
|
-
0.1155056680537256013533444839067835598622, 0.1155056680537256013533444839067835598622,
|
|
38
|
-
0.1074442701159656347825773424466062227946, 0.1074442701159656347825773424466062227946,
|
|
39
|
-
0.0976186521041138882698806644642471544279, 0.0976186521041138882698806644642471544279,
|
|
40
|
-
0.086190161531953275917185202983742667185, 0.086190161531953275917185202983742667185,
|
|
41
|
-
0.0733464814110803057340336152531165181193, 0.0733464814110803057340336152531165181193,
|
|
42
|
-
0.0592985849154367807463677585001085845412, 0.0592985849154367807463677585001085845412,
|
|
43
|
-
0.0442774388174198061686027482113382288593, 0.0442774388174198061686027482113382288593,
|
|
44
|
-
0.0285313886289336631813078159518782864491, 0.0285313886289336631813078159518782864491,
|
|
45
|
-
0.0123412297999871995468056670700372915759, 0.0123412297999871995468056670700372915759,
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
50
|
-
* @param points
|
|
51
|
-
* @returns
|
|
52
|
-
*/
|
|
53
|
-
const deriveBezier = (points: QuadPoints | CubicPoints) => {
|
|
54
|
-
const dpoints = [] as (DerivedCubicPoints | DerivedQuadPoints)[];
|
|
55
|
-
for (let p = points, d = p.length, c = d - 1; d > 1; d -= 1, c -= 1) {
|
|
56
|
-
const list = [] as unknown as DerivedCubicPoints | DerivedQuadPoints;
|
|
57
|
-
for (let j = 0; j < c; j += 1) {
|
|
58
|
-
list.push({
|
|
59
|
-
x: c * (p[j + 1].x - p[j].x),
|
|
60
|
-
y: c * (p[j + 1].y - p[j].y),
|
|
61
|
-
t: 0,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
dpoints.push(list);
|
|
65
|
-
p = list;
|
|
66
|
-
}
|
|
67
|
-
return dpoints;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
*
|
|
72
|
-
* @param points
|
|
73
|
-
* @param t
|
|
74
|
-
*/
|
|
75
|
-
const computeBezier = (points: DerivedQuadPoints | DerivedCubicPoints, t: number) => {
|
|
76
|
-
// shortcuts
|
|
77
|
-
/* istanbul ignore next @preserve */
|
|
78
|
-
if (t === 0) {
|
|
79
|
-
points[0].t = 0;
|
|
80
|
-
return points[0];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const order = points.length - 1;
|
|
84
|
-
|
|
85
|
-
/* istanbul ignore next @preserve */
|
|
86
|
-
if (t === 1) {
|
|
87
|
-
points[order].t = 1;
|
|
88
|
-
return points[order];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const mt = 1 - t;
|
|
92
|
-
let p = points as typeof points | [DerivedPoint, DerivedPoint, DerivedPoint, DerivedPoint];
|
|
93
|
-
|
|
94
|
-
// constant?
|
|
95
|
-
/* istanbul ignore next @preserve */
|
|
96
|
-
if (order === 0) {
|
|
97
|
-
points[0].t = t;
|
|
98
|
-
return points[0];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// linear?
|
|
102
|
-
/* istanbul ignore else @preserve */
|
|
103
|
-
if (order === 1) {
|
|
104
|
-
return {
|
|
105
|
-
x: mt * p[0].x + t * p[1].x,
|
|
106
|
-
y: mt * p[0].y + t * p[1].y,
|
|
107
|
-
t,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// quadratic/cubic curve?
|
|
112
|
-
const mt2 = mt * mt;
|
|
113
|
-
const t2 = t * t;
|
|
114
|
-
let a = 0;
|
|
115
|
-
let b = 0;
|
|
116
|
-
let c = 0;
|
|
117
|
-
let d = 0;
|
|
118
|
-
/* istanbul ignore else @preserve */
|
|
119
|
-
if (order === 2) {
|
|
120
|
-
p = [p[0], p[1], p[2], { x: 0, y: 0 } as DerivedPoint];
|
|
121
|
-
a = mt2;
|
|
122
|
-
b = mt * t * 2;
|
|
123
|
-
c = t2;
|
|
124
|
-
} else if (order === 3) {
|
|
125
|
-
a = mt2 * mt;
|
|
126
|
-
b = mt2 * t * 3;
|
|
127
|
-
c = mt * t2 * 3;
|
|
128
|
-
d = t * t2;
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
x: a * p[0].x + b * p[1].x + c * p[2].x + d * p[3].x,
|
|
132
|
-
y: a * p[0].y + b * p[1].y + c * p[2].y + d * p[3].y,
|
|
133
|
-
t,
|
|
134
|
-
};
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const calculateBezier = (derivativeFn: DeriveCallback, t: number) => {
|
|
138
|
-
const d = derivativeFn(t);
|
|
139
|
-
const l = d.x * d.x + d.y * d.y;
|
|
140
|
-
|
|
141
|
-
return Math.sqrt(l);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const bezierLength = (derivativeFn: DeriveCallback) => {
|
|
145
|
-
const z = 0.5;
|
|
146
|
-
const len = Tvalues.length;
|
|
147
|
-
|
|
148
|
-
let sum = 0;
|
|
149
|
-
|
|
150
|
-
for (let i = 0, t; i < len; i++) {
|
|
151
|
-
t = z * Tvalues[i] + z;
|
|
152
|
-
sum += Cvalues[i] * calculateBezier(derivativeFn, t);
|
|
153
|
-
}
|
|
154
|
-
return z * sum;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Returns the length of CubicBezier / Quad segment.
|
|
159
|
-
* @param curve cubic / quad bezier segment
|
|
160
|
-
*/
|
|
161
|
-
const getBezierLength = (curve: CubicCoordinates | QuadCoordinates) => {
|
|
162
|
-
const points = [] as unknown as CubicPoints | QuadPoints;
|
|
163
|
-
for (let idx = 0, len = curve.length, step = 2; idx < len; idx += step) {
|
|
164
|
-
points.push({
|
|
165
|
-
x: curve[idx],
|
|
166
|
-
y: curve[idx + 1],
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
const dpoints = deriveBezier(points);
|
|
170
|
-
return bezierLength((t: number) => {
|
|
171
|
-
return computeBezier(dpoints[0], t);
|
|
172
|
-
});
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
// Precision for consider cubic polynom as quadratic one
|
|
176
|
-
const CBEZIER_MINMAX_EPSILON = 0.00000001;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Returns the most extreme points in a Quad Bezier segment.
|
|
180
|
-
* @param A an array which consist of X/Y values
|
|
181
|
-
*/
|
|
182
|
-
// https://github.com/kpym/SVGPathy/blob/acd1a50c626b36d81969f6e98e8602e128ba4302/lib/box.js#L89
|
|
183
|
-
const minmaxQ = ([v1, cp, v2]: [number, number, number]) => {
|
|
184
|
-
const min = Math.min(v1, v2);
|
|
185
|
-
const max = Math.max(v1, v2);
|
|
186
|
-
|
|
187
|
-
/* istanbul ignore next @preserve */
|
|
188
|
-
if (cp >= v1 ? v2 >= cp : v2 <= cp) {
|
|
189
|
-
// if no extremum in ]0,1[
|
|
190
|
-
return [min, max] as PointTuple;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// check if the extremum E is min or max
|
|
194
|
-
const E = (v1 * v2 - cp * cp) / (v1 - 2 * cp + v2);
|
|
195
|
-
return (E < min ? [E, max] : [min, E]) as PointTuple;
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Returns the most extreme points in a Cubic Bezier segment.
|
|
200
|
-
* @param A an array which consist of X/Y values
|
|
201
|
-
* @see https://github.com/kpym/SVGPathy/blob/acd1a50c626b36d81969f6e98e8602e128ba4302/lib/box.js#L127
|
|
202
|
-
*/
|
|
203
|
-
const minmaxC = ([v1, cp1, cp2, v2]: [number, number, number, number]) => {
|
|
204
|
-
const K = v1 - 3 * cp1 + 3 * cp2 - v2;
|
|
205
|
-
|
|
206
|
-
// if the polynomial is (almost) quadratic and not cubic
|
|
207
|
-
/* istanbul ignore next @preserve */
|
|
208
|
-
if (Math.abs(K) < CBEZIER_MINMAX_EPSILON) {
|
|
209
|
-
if (v1 === v2 && v1 === cp1) {
|
|
210
|
-
// no curve, point targeting same location
|
|
211
|
-
return [v1, v2] as PointTuple;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return minmaxQ([v1, -0.5 * v1 + 1.5 * cp1, v1 - 3 * cp1 + 3 * cp2]);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// the reduced discriminant of the derivative
|
|
218
|
-
const T = -v1 * cp2 + v1 * v2 - cp1 * cp2 - cp1 * v2 + cp1 * cp1 + cp2 * cp2;
|
|
219
|
-
|
|
220
|
-
// if the polynomial is monotone in [0,1]
|
|
221
|
-
if (T <= 0) {
|
|
222
|
-
return [Math.min(v1, v2), Math.max(v1, v2)] as PointTuple;
|
|
223
|
-
}
|
|
224
|
-
const S = Math.sqrt(T);
|
|
225
|
-
|
|
226
|
-
// potential extrema
|
|
227
|
-
let min = Math.min(v1, v2);
|
|
228
|
-
let max = Math.max(v1, v2);
|
|
229
|
-
|
|
230
|
-
const L = v1 - 2 * cp1 + cp2;
|
|
231
|
-
// check local extrema
|
|
232
|
-
for (let R = (L + S) / K, i = 1; i <= 2; R = (L - S) / K, i++) {
|
|
233
|
-
// istanbul ignore next @preserve
|
|
234
|
-
if (R > 0 && R < 1) {
|
|
235
|
-
// if the extrema is for R in [0,1]
|
|
236
|
-
const Q =
|
|
237
|
-
v1 * (1 - R) * (1 - R) * (1 - R) + cp1 * 3 * (1 - R) * (1 - R) * R + cp2 * 3 * (1 - R) * R * R + v2 * R * R * R;
|
|
238
|
-
if (Q < min) {
|
|
239
|
-
min = Q;
|
|
240
|
-
}
|
|
241
|
-
if (Q > max) {
|
|
242
|
-
max = Q;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return [min, max] as PointTuple;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
export {
|
|
251
|
-
Cvalues,
|
|
252
|
-
Tvalues,
|
|
253
|
-
minmaxC,
|
|
254
|
-
minmaxQ,
|
|
255
|
-
getBezierLength,
|
|
256
|
-
bezierLength,
|
|
257
|
-
calculateBezier,
|
|
258
|
-
computeBezier,
|
|
259
|
-
deriveBezier,
|
|
260
|
-
CBEZIER_MINMAX_EPSILON,
|
|
261
|
-
};
|