modern-path2d 0.0.1 → 0.0.2

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/dist/index.mjs CHANGED
@@ -1,3 +1,970 @@
1
- const one = 1;
1
+ class Point2D {
2
+ constructor(x = 0, y = 0) {
3
+ this.x = x;
4
+ this.y = y;
5
+ }
6
+ set(x, y) {
7
+ this.x = x;
8
+ this.y = y;
9
+ return this;
10
+ }
11
+ add(point) {
12
+ this.x += point.x;
13
+ this.y += point.y;
14
+ return this;
15
+ }
16
+ sub(point) {
17
+ this.x -= point.x;
18
+ this.y -= point.y;
19
+ return this;
20
+ }
21
+ distanceTo(point) {
22
+ return Math.sqrt(this.distanceToSquared(point));
23
+ }
24
+ distanceToSquared(point) {
25
+ const dx = this.x - point.x;
26
+ const dy = this.y - point.y;
27
+ return dx * dx + dy * dy;
28
+ }
29
+ length() {
30
+ return Math.sqrt(this.x * this.x + this.y * this.y);
31
+ }
32
+ multiplyScalar(scalar) {
33
+ this.x *= scalar;
34
+ this.y *= scalar;
35
+ return this;
36
+ }
37
+ divideScalar(scalar) {
38
+ return this.multiplyScalar(1 / scalar);
39
+ }
40
+ subVectors(a, b) {
41
+ this.x = a.x - b.x;
42
+ this.y = a.y - b.y;
43
+ return this;
44
+ }
45
+ normalize() {
46
+ return this.divideScalar(this.length() || 1);
47
+ }
48
+ lerpVectors(v1, v2, alpha) {
49
+ this.x = v1.x + (v2.x - v1.x) * alpha;
50
+ this.y = v1.y + (v2.y - v1.y) * alpha;
51
+ return this;
52
+ }
53
+ equals(point) {
54
+ return this.x === point.x && this.y === point.y;
55
+ }
56
+ copy(point) {
57
+ this.x = point.x;
58
+ this.y = point.y;
59
+ return this;
60
+ }
61
+ clone() {
62
+ return new Point2D(this.x, this.y);
63
+ }
64
+ }
2
65
 
3
- export { one };
66
+ var __defProp$5 = Object.defineProperty;
67
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
68
+ var __publicField$5 = (obj, key, value) => {
69
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
70
+ return value;
71
+ };
72
+ class Curve {
73
+ constructor() {
74
+ __publicField$5(this, "arcLengthDivisions", 200);
75
+ __publicField$5(this, "_cacheArcLengths");
76
+ __publicField$5(this, "_needsUpdate", false);
77
+ }
78
+ getDivisions(divisions) {
79
+ return divisions;
80
+ }
81
+ getPointAt(u, output = new Point2D()) {
82
+ return this.getPoint(this.getUtoTmapping(u), output);
83
+ }
84
+ getPoints(divisions = 5) {
85
+ const points = [];
86
+ for (let i = 0; i <= divisions; i++) {
87
+ points.push(this.getPoint(i / divisions));
88
+ }
89
+ return points;
90
+ }
91
+ getSpacedPoints(divisions = 5) {
92
+ const points = [];
93
+ for (let i = 0; i <= divisions; i++) {
94
+ points.push(this.getPointAt(i / divisions));
95
+ }
96
+ return points;
97
+ }
98
+ getLength() {
99
+ const lengths = this.getLengths();
100
+ return lengths[lengths.length - 1];
101
+ }
102
+ getLengths(divisions = this.arcLengthDivisions) {
103
+ if (this._cacheArcLengths && this._cacheArcLengths.length === divisions + 1 && !this._needsUpdate) {
104
+ return this._cacheArcLengths;
105
+ }
106
+ this._needsUpdate = false;
107
+ const cache = [];
108
+ let current;
109
+ let last = this.getPoint(0);
110
+ let sum = 0;
111
+ cache.push(0);
112
+ for (let i = 1; i <= divisions; i++) {
113
+ current = this.getPoint(i / divisions);
114
+ sum += current.distanceTo(last);
115
+ cache.push(sum);
116
+ last = current;
117
+ }
118
+ this._cacheArcLengths = cache;
119
+ return cache;
120
+ }
121
+ updateArcLengths() {
122
+ this._needsUpdate = true;
123
+ this.getLengths();
124
+ }
125
+ getUtoTmapping(u, distance) {
126
+ const arcLengths = this.getLengths();
127
+ let i = 0;
128
+ const il = arcLengths.length;
129
+ let targetArcLength;
130
+ if (distance) {
131
+ targetArcLength = distance;
132
+ } else {
133
+ targetArcLength = u * arcLengths[il - 1];
134
+ }
135
+ let low = 0;
136
+ let high = il - 1;
137
+ let comparison;
138
+ while (low <= high) {
139
+ i = Math.floor(low + (high - low) / 2);
140
+ comparison = arcLengths[i] - targetArcLength;
141
+ if (comparison < 0) {
142
+ low = i + 1;
143
+ } else if (comparison > 0) {
144
+ high = i - 1;
145
+ } else {
146
+ high = i;
147
+ break;
148
+ }
149
+ }
150
+ i = high;
151
+ if (arcLengths[i] === targetArcLength) {
152
+ return i / (il - 1);
153
+ }
154
+ const lengthBefore = arcLengths[i];
155
+ const lengthAfter = arcLengths[i + 1];
156
+ const segmentLength = lengthAfter - lengthBefore;
157
+ const segmentFraction = (targetArcLength - lengthBefore) / segmentLength;
158
+ return (i + segmentFraction) / (il - 1);
159
+ }
160
+ getTangent(t, output = new Point2D()) {
161
+ const delta = 1e-4;
162
+ let t1 = t - delta;
163
+ let t2 = t + delta;
164
+ if (t1 < 0)
165
+ t1 = 0;
166
+ if (t2 > 1)
167
+ t2 = 1;
168
+ return output.copy(this.getPoint(t2)).sub(this.getPoint(t1)).normalize();
169
+ }
170
+ getTangentAt(u, output = new Point2D()) {
171
+ return this.getTangent(this.getUtoTmapping(u), output);
172
+ }
173
+ clone() {
174
+ return new this.constructor().copy(this);
175
+ }
176
+ copy(source) {
177
+ this.arcLengthDivisions = source.arcLengthDivisions;
178
+ return this;
179
+ }
180
+ }
181
+
182
+ class CircleCurve extends Curve {
183
+ constructor(center, radius, start = 0, end = Math.PI * 2) {
184
+ super();
185
+ this.center = center;
186
+ this.radius = radius;
187
+ this.start = start;
188
+ this.end = end;
189
+ }
190
+ getPole(min, max) {
191
+ min.x = Math.min(min.x, this.center.x - this.radius);
192
+ min.y = Math.min(min.y, this.center.y - this.radius);
193
+ max.x = Math.max(max.x, this.center.x + this.radius);
194
+ max.y = Math.max(max.y, this.center.y + this.radius);
195
+ }
196
+ getPoint(index) {
197
+ const { radius, center } = this;
198
+ return center.clone().add(this.getNormal(index).clone().multiplyScalar(radius));
199
+ }
200
+ getTangent(index) {
201
+ const { x, y } = this.getNormal(index);
202
+ return new Point2D(-y, x);
203
+ }
204
+ getNormal(index) {
205
+ const { start, end } = this;
206
+ const t = index * (end - start) + start - 0.5 * Math.PI;
207
+ return new Point2D(Math.cos(t), Math.sin(t));
208
+ }
209
+ toPathCommands() {
210
+ return [];
211
+ }
212
+ drawTo(_ctx) {
213
+ }
214
+ }
215
+
216
+ function catmullRom(t, p0, p1, p2, p3) {
217
+ const v0 = (p2 - p0) * 0.5;
218
+ const v1 = (p3 - p1) * 0.5;
219
+ const t2 = t * t;
220
+ const t3 = t * t2;
221
+ return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
222
+ }
223
+ function quadraticBezierP0(t, p) {
224
+ const k = 1 - t;
225
+ return k * k * p;
226
+ }
227
+ function quadraticBezierP1(t, p) {
228
+ return 2 * (1 - t) * t * p;
229
+ }
230
+ function quadraticBezierP2(t, p) {
231
+ return t * t * p;
232
+ }
233
+ function quadraticBezier(t, p0, p1, p2) {
234
+ return quadraticBezierP0(t, p0) + quadraticBezierP1(t, p1) + quadraticBezierP2(t, p2);
235
+ }
236
+ function cubicBezierP0(t, p) {
237
+ const k = 1 - t;
238
+ return k * k * k * p;
239
+ }
240
+ function cubicBezierP1(t, p) {
241
+ const k = 1 - t;
242
+ return 3 * k * k * t * p;
243
+ }
244
+ function cubicBezierP2(t, p) {
245
+ return 3 * (1 - t) * t * t * p;
246
+ }
247
+ function cubicBezierP3(t, p) {
248
+ return t * t * t * p;
249
+ }
250
+ function cubicBezier(t, p0, p1, p2, p3) {
251
+ return cubicBezierP0(t, p0) + cubicBezierP1(t, p1) + cubicBezierP2(t, p2) + cubicBezierP3(t, p3);
252
+ }
253
+
254
+ class CubicBezierCurve extends Curve {
255
+ constructor(v0 = new Point2D(), v1 = new Point2D(), v2 = new Point2D(), v3 = new Point2D()) {
256
+ super();
257
+ this.v0 = v0;
258
+ this.v1 = v1;
259
+ this.v2 = v2;
260
+ this.v3 = v3;
261
+ }
262
+ getPoint(t, output = new Point2D()) {
263
+ const { v0, v1, v2, v3 } = this;
264
+ output.set(
265
+ cubicBezier(t, v0.x, v1.x, v2.x, v3.x),
266
+ cubicBezier(t, v0.y, v1.y, v2.y, v3.y)
267
+ );
268
+ return output;
269
+ }
270
+ toPathCommands() {
271
+ return [];
272
+ }
273
+ drawTo(ctx) {
274
+ const { v0, v1, v2, v3 } = this;
275
+ ctx.moveTo(v0.x, v0.y);
276
+ ctx.bezierCurveTo(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y);
277
+ }
278
+ copy(source) {
279
+ super.copy(source);
280
+ this.v0.copy(source.v0);
281
+ this.v1.copy(source.v1);
282
+ this.v2.copy(source.v2);
283
+ this.v3.copy(source.v3);
284
+ return this;
285
+ }
286
+ }
287
+
288
+ class EllipseCurve extends Curve {
289
+ constructor(x = 0, y = 0, rx = 1, ry = 1, startAngle = 0, endAngle = Math.PI * 2, clockwise = false, rotation = 0) {
290
+ super();
291
+ this.x = x;
292
+ this.y = y;
293
+ this.rx = rx;
294
+ this.ry = ry;
295
+ this.startAngle = startAngle;
296
+ this.endAngle = endAngle;
297
+ this.clockwise = clockwise;
298
+ this.rotation = rotation;
299
+ }
300
+ getDivisions(divisions = 12) {
301
+ return divisions * 2;
302
+ }
303
+ getPoint(t, output = new Point2D()) {
304
+ const twoPi = Math.PI * 2;
305
+ let deltaAngle = this.endAngle - this.startAngle;
306
+ const samePoints = Math.abs(deltaAngle) < Number.EPSILON;
307
+ while (deltaAngle < 0)
308
+ deltaAngle += twoPi;
309
+ while (deltaAngle > twoPi)
310
+ deltaAngle -= twoPi;
311
+ if (deltaAngle < Number.EPSILON) {
312
+ if (samePoints) {
313
+ deltaAngle = 0;
314
+ } else {
315
+ deltaAngle = twoPi;
316
+ }
317
+ }
318
+ if (this.clockwise && !samePoints) {
319
+ if (deltaAngle === twoPi) {
320
+ deltaAngle = -twoPi;
321
+ } else {
322
+ deltaAngle = deltaAngle - twoPi;
323
+ }
324
+ }
325
+ const angle = this.startAngle + t * deltaAngle;
326
+ let _x = this.x + this.rx * Math.cos(angle);
327
+ let _y = this.y + this.ry * Math.sin(angle);
328
+ if (this.rotation !== 0) {
329
+ const cos = Math.cos(this.rotation);
330
+ const sin = Math.sin(this.rotation);
331
+ const tx = _x - this.x;
332
+ const ty = _y - this.y;
333
+ _x = tx * cos - ty * sin + this.x;
334
+ _y = tx * sin + ty * cos + this.y;
335
+ }
336
+ return output.set(_x, _y);
337
+ }
338
+ toPathCommands() {
339
+ const { x, y, rx, ry, startAngle, endAngle, clockwise } = this;
340
+ const startX = x + rx * Math.cos(startAngle);
341
+ const startY = y + ry * Math.sin(startAngle);
342
+ const endX = x + rx * Math.cos(endAngle);
343
+ const endY = y + ry * Math.sin(endAngle);
344
+ const largeArcFlag = (endAngle - startAngle) % (2 * Math.PI) > Math.PI ? 1 : 0;
345
+ const sweepFlag = clockwise ? 0 : 1;
346
+ return [
347
+ { type: "M", x: startX, y: startY },
348
+ { type: "A", rx, ry, xAxisRotation: 0, largeArcFlag, sweepFlag, x: endX, y: endY }
349
+ ];
350
+ }
351
+ drawTo(ctx) {
352
+ const { x, y, rx, ry, startAngle } = this;
353
+ const startX = x + rx * Math.cos(startAngle);
354
+ const startY = y + ry * Math.sin(startAngle);
355
+ ctx.moveTo(startX, startY);
356
+ ctx.arc(
357
+ this.x,
358
+ this.y,
359
+ this.rx,
360
+ this.startAngle,
361
+ this.endAngle,
362
+ !this.clockwise
363
+ );
364
+ }
365
+ copy(source) {
366
+ super.copy(source);
367
+ this.x = source.x;
368
+ this.y = source.y;
369
+ this.rx = source.rx;
370
+ this.ry = source.ry;
371
+ this.startAngle = source.startAngle;
372
+ this.endAngle = source.endAngle;
373
+ this.clockwise = source.clockwise;
374
+ this.rotation = source.rotation;
375
+ return this;
376
+ }
377
+ }
378
+
379
+ class LineCurve extends Curve {
380
+ constructor(v1 = new Point2D(), v2 = new Point2D()) {
381
+ super();
382
+ this.v1 = v1;
383
+ this.v2 = v2;
384
+ }
385
+ getDivisions() {
386
+ return 1;
387
+ }
388
+ getPoint(t, output = new Point2D()) {
389
+ if (t === 1) {
390
+ output.copy(this.v2);
391
+ } else {
392
+ output.copy(this.v2).sub(this.v1);
393
+ output.multiplyScalar(t).add(this.v1);
394
+ }
395
+ return output;
396
+ }
397
+ getPointAt(u, output = new Point2D()) {
398
+ return this.getPoint(u, output);
399
+ }
400
+ getTangent(t, output = new Point2D()) {
401
+ return output.subVectors(this.v2, this.v1).normalize();
402
+ }
403
+ getTangentAt(u, output = new Point2D()) {
404
+ return this.getTangent(u, output);
405
+ }
406
+ toPathCommands() {
407
+ return [
408
+ { type: "M", x: this.v1.x, y: this.v1.y },
409
+ { type: "L", x: this.v2.x, y: this.v2.y }
410
+ ];
411
+ }
412
+ drawTo(ctx) {
413
+ const { v1, v2 } = this;
414
+ ctx.moveTo(v1.x, v1.y);
415
+ ctx.lineTo(v2.x, v2.y);
416
+ }
417
+ copy(source) {
418
+ super.copy(source);
419
+ this.v1.copy(source.v1);
420
+ this.v2.copy(source.v2);
421
+ return this;
422
+ }
423
+ }
424
+
425
+ var __defProp$4 = Object.defineProperty;
426
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
427
+ var __publicField$4 = (obj, key, value) => {
428
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
429
+ return value;
430
+ };
431
+ class HeartCurve extends Curve {
432
+ constructor(center, size, start = 0, end = 1) {
433
+ super();
434
+ this.center = center;
435
+ this.size = size;
436
+ this.start = start;
437
+ this.end = end;
438
+ __publicField$4(this, "curves");
439
+ __publicField$4(this, "pointT", 0);
440
+ const { x, y } = this.center;
441
+ const A = new Point2D(x + 0.5 * this.size, y - 0.5 * this.size);
442
+ const t = new Point2D(x - 0.5 * this.size, y - 0.5 * this.size);
443
+ const i = new Point2D(x, y + 0.5 * this.size);
444
+ const curve1 = new CircleCurve(A, Math.SQRT1_2 * this.size, -0.25 * Math.PI, 0.75 * Math.PI);
445
+ const curve5 = new CircleCurve(t, Math.SQRT1_2 * this.size, -0.75 * Math.PI, 0.25 * Math.PI);
446
+ const curve3 = new CircleCurve(i, 0.5 * Math.SQRT1_2 * this.size, 0.75 * Math.PI, 1.25 * Math.PI);
447
+ const e = new Point2D(x, y + this.size);
448
+ const l = new Point2D(x + this.size, y);
449
+ const c = new Point2D().lerpVectors(l, e, 0.75);
450
+ const h = new Point2D(x - this.size, y);
451
+ const a = new Point2D().lerpVectors(h, e, 0.75);
452
+ const curve2 = new LineCurve(l, c);
453
+ const curve4 = new LineCurve(a, h);
454
+ this.curves = [curve1, curve2, curve3, curve4, curve5];
455
+ }
456
+ getPoint(value) {
457
+ return this.getCurrentLine(value).getPoint(this.pointT);
458
+ }
459
+ getPointAt(value) {
460
+ return this.getPoint(value);
461
+ }
462
+ getCurrentLine(value) {
463
+ let val = (value * (this.end - this.start) + this.start) % 1;
464
+ val < 0 && (val += 1);
465
+ val *= 9 * Math.PI / 8 + 1.5;
466
+ let index;
467
+ const t = 0.5 * Math.PI;
468
+ if (val < t) {
469
+ index = 0;
470
+ this.pointT = val / t;
471
+ } else if (val < t + 0.75) {
472
+ index = 1;
473
+ this.pointT = (val - t) / 0.75;
474
+ } else if (val < 5 * Math.PI / 8 + 0.75) {
475
+ index = 2;
476
+ this.pointT = (val - t - 0.75) / (Math.PI / 8);
477
+ } else if (val < 5 * Math.PI / 8 + 1.5) {
478
+ index = 3;
479
+ this.pointT = (val - 5 * Math.PI / 8 - 0.75) / 0.75;
480
+ } else {
481
+ index = 4;
482
+ this.pointT = (val - 5 * Math.PI / 8 - 1.5) / t;
483
+ }
484
+ return this.curves[index];
485
+ }
486
+ getTangent(value) {
487
+ return this.getCurrentLine(value).getTangent(this.pointT).normalize();
488
+ }
489
+ getNormal(value) {
490
+ const line = this.getCurrentLine(value);
491
+ return new Point2D(line.v2.y - line.v1.y, -(line.v2.x - line.v1.x)).normalize();
492
+ }
493
+ toPathCommands() {
494
+ return this.curves.flatMap((curve) => curve.toPathCommands());
495
+ }
496
+ drawTo(ctx) {
497
+ this.curves.forEach((curve) => curve.drawTo(ctx));
498
+ }
499
+ }
500
+
501
+ var __defProp$3 = Object.defineProperty;
502
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
503
+ var __publicField$3 = (obj, key, value) => {
504
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
505
+ return value;
506
+ };
507
+ class PloygonCurve extends Curve {
508
+ constructor(center, radius = 0, num = 0, start = 0, end = 1) {
509
+ super();
510
+ this.center = center;
511
+ this.radius = radius;
512
+ this.num = num;
513
+ this.start = start;
514
+ this.end = end;
515
+ __publicField$3(this, "curves", []);
516
+ __publicField$3(this, "points", []);
517
+ for (let i = 0; i < this.num; i++) {
518
+ let radian = i * 2 * Math.PI / this.num;
519
+ radian -= 0.5 * Math.PI;
520
+ const point = new Point2D(this.radius * Math.cos(radian), this.radius * Math.sin(radian));
521
+ point.add(this.center);
522
+ this.points.push(point);
523
+ }
524
+ for (let i = 0; i < this.num; i++) {
525
+ this.curves.push(new LineCurve(this.points[i], this.points[(i + 1) % this.num]));
526
+ }
527
+ }
528
+ getPoint(value) {
529
+ this.getCurrentLine(value);
530
+ return this.currentLine.getPoint(this.pointK);
531
+ }
532
+ getPointAt(value) {
533
+ return this.getPoint(value);
534
+ }
535
+ getCurrentLine(value) {
536
+ let pos = (value * (this.end - this.start) + this.start) % 1;
537
+ pos < 0 && (pos += 1);
538
+ const v = pos * this.num;
539
+ const index = Math.floor(v);
540
+ this.pointK = v - index;
541
+ this.currentLine = this.curves[index];
542
+ return this.currentLine;
543
+ }
544
+ getTangent(value) {
545
+ return this.getCurrentLine(value).getTangent(0).normalize();
546
+ }
547
+ getNormal(value) {
548
+ const line = this.getCurrentLine(value);
549
+ return new Point2D(line.v2.y - line.v1.y, -(line.v2.x - line.v1.x)).normalize();
550
+ }
551
+ toPathCommands() {
552
+ return this.curves.flatMap((curve) => curve.toPathCommands());
553
+ }
554
+ drawTo(ctx) {
555
+ this.curves.forEach((curve) => curve.drawTo(ctx));
556
+ }
557
+ }
558
+
559
+ class QuadraticBezierCurve extends Curve {
560
+ constructor(v0 = new Point2D(), v1 = new Point2D(), v2 = new Point2D()) {
561
+ super();
562
+ this.v0 = v0;
563
+ this.v1 = v1;
564
+ this.v2 = v2;
565
+ }
566
+ getPoint(t, output = new Point2D()) {
567
+ const { v0, v1, v2 } = this;
568
+ output.set(
569
+ quadraticBezier(t, v0.x, v1.x, v2.x),
570
+ quadraticBezier(t, v0.y, v1.y, v2.y)
571
+ );
572
+ return output;
573
+ }
574
+ toPathCommands() {
575
+ return [];
576
+ }
577
+ drawTo(ctx) {
578
+ const { v0, v1, v2 } = this;
579
+ ctx.moveTo(v0.x, v0.y);
580
+ ctx.quadraticCurveTo(v1.x, v1.y, v2.x, v2.y);
581
+ }
582
+ copy(source) {
583
+ super.copy(source);
584
+ this.v0.copy(source.v0);
585
+ this.v1.copy(source.v1);
586
+ this.v2.copy(source.v2);
587
+ return this;
588
+ }
589
+ }
590
+
591
+ var __defProp$2 = Object.defineProperty;
592
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
593
+ var __publicField$2 = (obj, key, value) => {
594
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
595
+ return value;
596
+ };
597
+ class RectangularCurve extends Curve {
598
+ constructor(center, rx, aspectRatio = 1, start = 0, end = 1) {
599
+ super();
600
+ this.center = center;
601
+ this.rx = rx;
602
+ this.aspectRatio = aspectRatio;
603
+ this.start = start;
604
+ this.end = end;
605
+ __publicField$2(this, "curves", []);
606
+ __publicField$2(this, "pointT", 0);
607
+ const { x, y } = this.center;
608
+ const offsetX = this.rx;
609
+ const offsetY = this.rx / this.aspectRatio;
610
+ const points = [
611
+ new Point2D(x - offsetX, y - offsetY),
612
+ new Point2D(x + offsetX, y - offsetY),
613
+ new Point2D(x + offsetX, y + offsetY),
614
+ new Point2D(x - offsetX, y + offsetY)
615
+ ];
616
+ for (let i = 0; i < 4; i++) {
617
+ this.curves.push(new LineCurve(points[i], points[(i + 1) % 4]));
618
+ }
619
+ }
620
+ get x() {
621
+ return this.center.x - this.rx;
622
+ }
623
+ get y() {
624
+ return this.center.y - this.rx / this.aspectRatio;
625
+ }
626
+ get width() {
627
+ return this.rx * 2;
628
+ }
629
+ get height() {
630
+ return this.rx / this.aspectRatio * 2;
631
+ }
632
+ getPoint(t) {
633
+ return this.getCurrentLine(t).getPoint(this.pointT);
634
+ }
635
+ getPointAt(u) {
636
+ return this.getPoint(u);
637
+ }
638
+ getCurrentLine(t) {
639
+ let flag = (t * (this.end - this.start) + this.start) % 1;
640
+ flag < 0 && (flag += 1);
641
+ flag *= (1 + this.aspectRatio) * 2;
642
+ let i;
643
+ if (flag < this.aspectRatio) {
644
+ i = 0;
645
+ this.pointT = flag / this.aspectRatio;
646
+ } else if (flag < this.aspectRatio + 1) {
647
+ i = 1;
648
+ this.pointT = (flag - this.aspectRatio) / 1;
649
+ } else if (flag < 2 * this.aspectRatio + 1) {
650
+ i = 2;
651
+ this.pointT = (flag - this.aspectRatio - 1) / this.aspectRatio;
652
+ } else {
653
+ i = 3;
654
+ this.pointT = (flag - 2 * this.aspectRatio - 1) / 1;
655
+ }
656
+ return this.curves[i];
657
+ }
658
+ getTangent(t) {
659
+ return this.getCurrentLine(t).getTangent(0).normalize();
660
+ }
661
+ getNormal(value) {
662
+ const { v1, v2 } = this.getCurrentLine(value);
663
+ return new Point2D(v2.y - v1.y, -(v2.x - v1.x)).normalize();
664
+ }
665
+ toPathCommands() {
666
+ return this.curves.flatMap((curve) => curve.toPathCommands());
667
+ }
668
+ drawTo(ctx) {
669
+ this.curves.forEach((curve) => curve.drawTo(ctx));
670
+ }
671
+ }
672
+
673
+ class SplineCurve extends Curve {
674
+ constructor(points = []) {
675
+ super();
676
+ this.points = points;
677
+ }
678
+ getDivisions(divisions = 12) {
679
+ return divisions * this.points.length;
680
+ }
681
+ getPoint(t, output = new Point2D()) {
682
+ const { points } = this;
683
+ const p = (points.length - 1) * t;
684
+ const _p = Math.floor(p);
685
+ const weight = p - _p;
686
+ const p0 = points[_p === 0 ? _p : _p - 1];
687
+ const p1 = points[_p];
688
+ const p2 = points[_p > points.length - 2 ? points.length - 1 : _p + 1];
689
+ const p3 = points[_p > points.length - 3 ? points.length - 1 : _p + 2];
690
+ output.set(
691
+ catmullRom(weight, p0.x, p1.x, p2.x, p3.x),
692
+ catmullRom(weight, p0.y, p1.y, p2.y, p3.y)
693
+ );
694
+ return output;
695
+ }
696
+ toPathCommands() {
697
+ return [];
698
+ }
699
+ drawTo(_ctx) {
700
+ }
701
+ copy(source) {
702
+ super.copy(source);
703
+ this.points = [];
704
+ for (let i = 0, l = source.points.length; i < l; i++) {
705
+ const point = source.points[i];
706
+ this.points.push(point.clone());
707
+ }
708
+ return this;
709
+ }
710
+ }
711
+
712
+ var __defProp$1 = Object.defineProperty;
713
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
714
+ var __publicField$1 = (obj, key, value) => {
715
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
716
+ return value;
717
+ };
718
+ class CurvePath extends Curve {
719
+ constructor(points) {
720
+ super();
721
+ __publicField$1(this, "curves", []);
722
+ __publicField$1(this, "currentPoint", new Point2D());
723
+ __publicField$1(this, "autoClose", false);
724
+ __publicField$1(this, "_cacheLengths", []);
725
+ if (points) {
726
+ this.setFromPoints(points);
727
+ }
728
+ }
729
+ addCurve(curve) {
730
+ this.curves.push(curve);
731
+ return this;
732
+ }
733
+ closePath() {
734
+ const start = this.curves[0].getPoint(0);
735
+ const end = this.curves[this.curves.length - 1].getPoint(1);
736
+ if (!start.equals(end)) {
737
+ this.curves.push(new LineCurve(end, start));
738
+ }
739
+ return this;
740
+ }
741
+ getPoint(position, output = new Point2D()) {
742
+ const d = position * this.getLength();
743
+ const curveLengths = this.getCurveLengths();
744
+ let i = 0;
745
+ while (i < curveLengths.length) {
746
+ if (curveLengths[i] >= d) {
747
+ const diff = curveLengths[i] - d;
748
+ const curve = this.curves[i];
749
+ const segmentLength = curve.getLength();
750
+ return curve.getPointAt(segmentLength === 0 ? 0 : 1 - diff / segmentLength, output);
751
+ }
752
+ i++;
753
+ }
754
+ return output;
755
+ }
756
+ getLength() {
757
+ const lengths = this.getCurveLengths();
758
+ return lengths[lengths.length - 1];
759
+ }
760
+ updateArcLengths() {
761
+ super.updateArcLengths();
762
+ this._cacheLengths = [];
763
+ this.getCurveLengths();
764
+ }
765
+ getCurveLengths() {
766
+ if (this._cacheLengths.length === this.curves.length) {
767
+ return this._cacheLengths;
768
+ }
769
+ const lengths = [];
770
+ let sums = 0;
771
+ for (let i = 0, l = this.curves.length; i < l; i++) {
772
+ sums += this.curves[i].getLength();
773
+ lengths.push(sums);
774
+ }
775
+ this._cacheLengths = lengths;
776
+ return lengths;
777
+ }
778
+ getSpacedPoints(divisions = 40) {
779
+ const points = [];
780
+ for (let i = 0; i <= divisions; i++) {
781
+ points.push(this.getPoint(i / divisions));
782
+ }
783
+ if (this.autoClose) {
784
+ points.push(points[0]);
785
+ }
786
+ return points;
787
+ }
788
+ getPoints(divisions = 12) {
789
+ const points = [];
790
+ let last;
791
+ for (let i = 0, curves = this.curves; i < curves.length; i++) {
792
+ const curve = curves[i];
793
+ const pts = curve.getPoints(curve.getDivisions(divisions));
794
+ for (let i2 = 0; i2 < pts.length; i2++) {
795
+ const point = pts[i2];
796
+ if (last && last.equals(point))
797
+ continue;
798
+ points.push(point);
799
+ last = point;
800
+ }
801
+ }
802
+ if (this.autoClose && points.length > 1 && !points[points.length - 1].equals(points[0])) {
803
+ points.push(points[0]);
804
+ }
805
+ return points;
806
+ }
807
+ setFromPoints(points) {
808
+ this.moveTo(points[0].x, points[0].y);
809
+ for (let i = 1, l = points.length; i < l; i++) {
810
+ this.lineTo(points[i].x, points[i].y);
811
+ }
812
+ return this;
813
+ }
814
+ bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
815
+ this.curves.push(
816
+ new CubicBezierCurve(
817
+ this.currentPoint.clone(),
818
+ new Point2D(cp1x, cp1y),
819
+ new Point2D(cp2x, cp2y),
820
+ new Point2D(x, y)
821
+ )
822
+ );
823
+ this.currentPoint.set(x, y);
824
+ return this;
825
+ }
826
+ lineTo(x, y) {
827
+ const curve = new LineCurve(this.currentPoint.clone(), new Point2D(x, y));
828
+ this.curves.push(curve);
829
+ this.currentPoint.set(x, y);
830
+ return this;
831
+ }
832
+ moveTo(x, y) {
833
+ this.currentPoint.set(x, y);
834
+ return this;
835
+ }
836
+ quadraticCurveTo(cpx, cpy, x, y) {
837
+ this.curves.push(
838
+ new QuadraticBezierCurve(
839
+ this.currentPoint.clone(),
840
+ new Point2D(cpx, cpy),
841
+ new Point2D(x, y)
842
+ )
843
+ );
844
+ this.currentPoint.set(x, y);
845
+ return this;
846
+ }
847
+ rect(x, y, w, h) {
848
+ this.curves.push(
849
+ new RectangularCurve(
850
+ new Point2D(x + w / 2, y + h / 2),
851
+ w / 2,
852
+ w / h
853
+ )
854
+ );
855
+ this.currentPoint.set(x, y);
856
+ return this;
857
+ }
858
+ splineThru(points) {
859
+ const npts = [this.currentPoint.clone()].concat(points);
860
+ this.curves.push(new SplineCurve(npts));
861
+ this.currentPoint.copy(points[points.length - 1]);
862
+ return this;
863
+ }
864
+ arc(x, y, radius, startAngle, endAngle, clockwise = false) {
865
+ const point = this.currentPoint;
866
+ this.absarc(x + point.x, y + point.y, radius, startAngle, endAngle, clockwise);
867
+ return this;
868
+ }
869
+ absarc(x, y, radius, startAngle, endAngle, clockwise = false) {
870
+ this.absellipse(x, y, radius, radius, startAngle, endAngle, clockwise);
871
+ return this;
872
+ }
873
+ ellipse(x, y, xRadius, yRadius, startAngle, endAngle, clockwise = false, rotation = 0) {
874
+ const point = this.currentPoint;
875
+ this.absellipse(x + point.x, y + point.y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
876
+ return this;
877
+ }
878
+ absellipse(x, y, xRadius, yRadius, startAngle, endAngle, clockwise = false, rotation = 0) {
879
+ const curve = new EllipseCurve(x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
880
+ if (this.curves.length > 0) {
881
+ const firstPoint = curve.getPoint(0);
882
+ if (!firstPoint.equals(this.currentPoint)) {
883
+ this.lineTo(firstPoint.x, firstPoint.y);
884
+ }
885
+ }
886
+ this.curves.push(curve);
887
+ this.currentPoint.copy(curve.getPoint(1));
888
+ return this;
889
+ }
890
+ toPathCommands() {
891
+ return this.curves.flatMap((curve) => curve.toPathCommands());
892
+ }
893
+ drawTo(ctx) {
894
+ this.curves.forEach((curve) => curve.drawTo(ctx));
895
+ }
896
+ copy(source) {
897
+ super.copy(source);
898
+ this.curves = [];
899
+ for (let i = 0, l = source.curves.length; i < l; i++) {
900
+ const curve = source.curves[i];
901
+ this.curves.push(curve.clone());
902
+ }
903
+ this.autoClose = source.autoClose;
904
+ this.currentPoint.copy(source.currentPoint);
905
+ return this;
906
+ }
907
+ }
908
+
909
+ var __defProp = Object.defineProperty;
910
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
911
+ var __publicField = (obj, key, value) => {
912
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
913
+ return value;
914
+ };
915
+ class Path2D {
916
+ constructor() {
917
+ __publicField(this, "currentPath", new CurvePath());
918
+ __publicField(this, "paths", [this.currentPath]);
919
+ }
920
+ arc(x, y, radius, startAngle, endAngle, counterclockwise) {
921
+ this.currentPath.absarc(x, y, radius, startAngle, endAngle, !counterclockwise);
922
+ return this;
923
+ }
924
+ bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
925
+ this.currentPath.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
926
+ return this;
927
+ }
928
+ lineTo(x, y) {
929
+ this.currentPath.lineTo(x, y);
930
+ return this;
931
+ }
932
+ moveTo(x, y) {
933
+ this.currentPath = new CurvePath();
934
+ this.paths.push(this.currentPath);
935
+ this.currentPath.moveTo(x, y);
936
+ return this;
937
+ }
938
+ quadraticCurveTo(cpx, cpy, x, y) {
939
+ this.currentPath.quadraticCurveTo(cpx, cpy, x, y);
940
+ return this;
941
+ }
942
+ rect(x, y, w, h) {
943
+ this.currentPath.rect(x, y, w, h);
944
+ return this;
945
+ }
946
+ splineThru(points) {
947
+ this.currentPath.splineThru(points);
948
+ return this;
949
+ }
950
+ toPathCommands() {
951
+ return this.paths.flatMap((path) => path.curves.flatMap((curve) => curve.toPathCommands()));
952
+ }
953
+ drawTo(ctx) {
954
+ this.paths.forEach((path) => {
955
+ path.curves.forEach((curve) => {
956
+ curve.drawTo(ctx);
957
+ });
958
+ });
959
+ }
960
+ strokeTo(ctx) {
961
+ this.drawTo(ctx);
962
+ ctx.stroke();
963
+ }
964
+ fillTo(ctx) {
965
+ this.drawTo(ctx);
966
+ ctx.fill();
967
+ }
968
+ }
969
+
970
+ export { CircleCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, HeartCurve, LineCurve, Path2D, PloygonCurve, Point2D, QuadraticBezierCurve, RectangularCurve, SplineCurve, catmullRom, cubicBezier, quadraticBezier };