poly-extrude 0.2.0 → 0.4.0
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/poly-extrude.js +2102 -62
- package/dist/poly-extrude.js.map +1 -1
- package/dist/poly-extrude.min.js +2 -2
- package/dist/poly-extrude.mjs +2102 -63
- package/index.js +2 -1
- package/package.json +3 -2
- package/readme.md +59 -1
- package/src/math/Curve.js +415 -0
- package/src/math/Interpolations.js +80 -0
- package/src/math/Matrix4.js +914 -0
- package/src/math/QuadraticBezierCurve3.js +76 -0
- package/src/math/Vector3.js +711 -0
- package/src/path/PathPoint.js +41 -0
- package/src/path/PathPointList.js +251 -0
- package/src/path.js +259 -0
- package/src/polyline.js +100 -20
package/index.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { extrudePolygons } from './src/polygon';
|
2
2
|
import { extrudePolylines, expandLine } from './src/polyline';
|
3
3
|
import { cylinder } from './src/cylinder';
|
4
|
-
|
4
|
+
import { expandPaths } from './src/path';
|
5
|
+
export { extrudePolygons, extrudePolylines, expandLine, cylinder, expandPaths };
|
package/package.json
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
{
|
2
2
|
"name": "poly-extrude",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/poly-extrude.js",
|
6
6
|
"module": "dist/poly-extrude.mjs",
|
7
7
|
"scripts": {
|
8
8
|
"test": "echo \"Error: no test specified\" && exit 1",
|
9
9
|
"lint": "eslint src/**/*.js",
|
10
|
-
"build": "npm run lint && cross-env NODE_ENV=dev rollup -c"
|
10
|
+
"build": "npm run lint && cross-env NODE_ENV=dev rollup -c",
|
11
|
+
"dev": "npm run lint && cross-env NODE_ENV=dev rollup -c -w"
|
11
12
|
},
|
12
13
|
"repository": {
|
13
14
|
"type": "git",
|
package/readme.md
CHANGED
@@ -22,6 +22,8 @@ Extrude polygons/polylines. Born in [maptalks.three](https://github.com/maptalks
|
|
22
22
|

|
23
23
|
[spring](https://deyihu.github.io/poly-extrude/test/spring.html)<br>
|
24
24
|

|
25
|
+
[expand paths](https://deyihu.github.io/poly-extrude/test/expand-paths-brige.html)<br>
|
26
|
+

|
25
27
|
|
26
28
|
## Install
|
27
29
|
|
@@ -45,7 +47,8 @@ pnpm i poly-extrude
|
|
45
47
|
import {
|
46
48
|
extrudePolygons,
|
47
49
|
extrudePolylines,
|
48
|
-
cylinder
|
50
|
+
cylinder,
|
51
|
+
expandPaths
|
49
52
|
} from 'poly-extrude';
|
50
53
|
const polygons = [
|
51
54
|
//polygon
|
@@ -116,6 +119,34 @@ pnpm i poly-extrude
|
|
116
119
|
indices
|
117
120
|
} = result;
|
118
121
|
//do something
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
const polylines = [
|
126
|
+
// polyline
|
127
|
+
[
|
128
|
+
[x, y],
|
129
|
+
[x, y], ...........
|
130
|
+
],
|
131
|
+
//polyline
|
132
|
+
[
|
133
|
+
[x, y],
|
134
|
+
[x, y], ...........
|
135
|
+
],
|
136
|
+
];
|
137
|
+
|
138
|
+
const result = expandPaths(polylines, {
|
139
|
+
cornerRadius: 0.5,
|
140
|
+
lineWidth: 2
|
141
|
+
});
|
142
|
+
const {
|
143
|
+
positon,
|
144
|
+
normal,
|
145
|
+
uv,
|
146
|
+
indices
|
147
|
+
} = result;
|
148
|
+
//do something
|
149
|
+
|
119
150
|
```
|
120
151
|
|
121
152
|
### CDN
|
@@ -193,5 +224,32 @@ pnpm i poly-extrude
|
|
193
224
|
indices
|
194
225
|
} = result;
|
195
226
|
//do something
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
const polylines = [
|
231
|
+
// polyline
|
232
|
+
[
|
233
|
+
[x, y],
|
234
|
+
[x, y], ...........
|
235
|
+
],
|
236
|
+
//polyline
|
237
|
+
[
|
238
|
+
[x, y],
|
239
|
+
[x, y], ...........
|
240
|
+
],
|
241
|
+
];
|
242
|
+
|
243
|
+
const result = polyextrude.expandPaths(polylines, {
|
244
|
+
cornerRadius: 0.5,
|
245
|
+
lineWidth: 2
|
246
|
+
});
|
247
|
+
const {
|
248
|
+
positon,
|
249
|
+
normal,
|
250
|
+
uv,
|
251
|
+
indices
|
252
|
+
} = result;
|
253
|
+
//do something
|
196
254
|
</script>
|
197
255
|
```
|
@@ -0,0 +1,415 @@
|
|
1
|
+
|
2
|
+
// code copy from https://github.com/mrdoob/three.js/blob/dev/src/extras/core/Curve.js
|
3
|
+
// import * as MathUtils from '../../math/MathUtils.js';
|
4
|
+
// import { Vector2 } from '../../math/Vector2.js';
|
5
|
+
// import { Vector3 } from '../../math/Vector3.js';
|
6
|
+
// import { Matrix4 } from '../../math/Matrix4.js';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Extensible curve object.
|
10
|
+
*
|
11
|
+
* Some common of curve methods:
|
12
|
+
* .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
|
13
|
+
* .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
|
14
|
+
* .getPoints(), .getSpacedPoints()
|
15
|
+
* .getLength()
|
16
|
+
* .updateArcLengths()
|
17
|
+
*
|
18
|
+
* This following curves inherit from THREE.Curve:
|
19
|
+
*
|
20
|
+
* -- 2D curves --
|
21
|
+
* THREE.ArcCurve
|
22
|
+
* THREE.CubicBezierCurve
|
23
|
+
* THREE.EllipseCurve
|
24
|
+
* THREE.LineCurve
|
25
|
+
* THREE.QuadraticBezierCurve
|
26
|
+
* THREE.SplineCurve
|
27
|
+
*
|
28
|
+
* -- 3D curves --
|
29
|
+
* THREE.CatmullRomCurve3
|
30
|
+
* THREE.CubicBezierCurve3
|
31
|
+
* THREE.LineCurve3
|
32
|
+
* THREE.QuadraticBezierCurve3
|
33
|
+
*
|
34
|
+
* A series of curves can be represented as a THREE.CurvePath.
|
35
|
+
*
|
36
|
+
**/
|
37
|
+
|
38
|
+
class Curve {
|
39
|
+
|
40
|
+
constructor() {
|
41
|
+
|
42
|
+
this.type = 'Curve';
|
43
|
+
|
44
|
+
this.arcLengthDivisions = 200;
|
45
|
+
|
46
|
+
}
|
47
|
+
|
48
|
+
// Virtual base class method to overwrite and implement in subclasses
|
49
|
+
|
50
|
+
getPoint() {
|
51
|
+
|
52
|
+
console.warn('THREE.Curve: .getPoint() not implemented.');
|
53
|
+
return null;
|
54
|
+
|
55
|
+
}
|
56
|
+
|
57
|
+
// Get point at relative position in curve according to arc length
|
58
|
+
// - u [0 .. 1]
|
59
|
+
|
60
|
+
getPointAt(u, optionalTarget) {
|
61
|
+
|
62
|
+
const t = this.getUtoTmapping(u);
|
63
|
+
return this.getPoint(t, optionalTarget);
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
// Get sequence of points using getPoint( t )
|
68
|
+
|
69
|
+
getPoints(divisions = 5) {
|
70
|
+
|
71
|
+
const points = [];
|
72
|
+
|
73
|
+
for (let d = 0; d <= divisions; d++) {
|
74
|
+
|
75
|
+
points.push(this.getPoint(d / divisions));
|
76
|
+
|
77
|
+
}
|
78
|
+
|
79
|
+
return points;
|
80
|
+
|
81
|
+
}
|
82
|
+
|
83
|
+
// // Get sequence of points using getPointAt( u )
|
84
|
+
|
85
|
+
// getSpacedPoints(divisions = 5) {
|
86
|
+
|
87
|
+
// const points = [];
|
88
|
+
|
89
|
+
// for (let d = 0; d <= divisions; d++) {
|
90
|
+
|
91
|
+
// points.push(this.getPointAt(d / divisions));
|
92
|
+
|
93
|
+
// }
|
94
|
+
|
95
|
+
// return points;
|
96
|
+
|
97
|
+
// }
|
98
|
+
|
99
|
+
// Get total curve arc length
|
100
|
+
|
101
|
+
getLength() {
|
102
|
+
|
103
|
+
const lengths = this.getLengths();
|
104
|
+
return lengths[lengths.length - 1];
|
105
|
+
|
106
|
+
}
|
107
|
+
|
108
|
+
// Get list of cumulative segment lengths
|
109
|
+
|
110
|
+
getLengths(divisions = this.arcLengthDivisions) {
|
111
|
+
|
112
|
+
if (this.cacheArcLengths &&
|
113
|
+
(this.cacheArcLengths.length === divisions + 1) &&
|
114
|
+
!this.needsUpdate) {
|
115
|
+
|
116
|
+
return this.cacheArcLengths;
|
117
|
+
|
118
|
+
}
|
119
|
+
|
120
|
+
this.needsUpdate = false;
|
121
|
+
|
122
|
+
const cache = [];
|
123
|
+
let current, last = this.getPoint(0);
|
124
|
+
let sum = 0;
|
125
|
+
|
126
|
+
cache.push(0);
|
127
|
+
|
128
|
+
for (let p = 1; p <= divisions; p++) {
|
129
|
+
|
130
|
+
current = this.getPoint(p / divisions);
|
131
|
+
sum += current.distanceTo(last);
|
132
|
+
cache.push(sum);
|
133
|
+
last = current;
|
134
|
+
|
135
|
+
}
|
136
|
+
|
137
|
+
this.cacheArcLengths = cache;
|
138
|
+
|
139
|
+
return cache; // { sums: cache, sum: sum }; Sum is in the last element.
|
140
|
+
|
141
|
+
}
|
142
|
+
|
143
|
+
// updateArcLengths() {
|
144
|
+
|
145
|
+
// this.needsUpdate = true;
|
146
|
+
// this.getLengths();
|
147
|
+
|
148
|
+
// }
|
149
|
+
|
150
|
+
// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
|
151
|
+
|
152
|
+
getUtoTmapping(u, distance) {
|
153
|
+
|
154
|
+
const arcLengths = this.getLengths();
|
155
|
+
|
156
|
+
let i = 0;
|
157
|
+
const il = arcLengths.length;
|
158
|
+
|
159
|
+
let targetArcLength; // The targeted u distance value to get
|
160
|
+
|
161
|
+
if (distance) {
|
162
|
+
|
163
|
+
targetArcLength = distance;
|
164
|
+
|
165
|
+
} else {
|
166
|
+
|
167
|
+
targetArcLength = u * arcLengths[il - 1];
|
168
|
+
|
169
|
+
}
|
170
|
+
|
171
|
+
// binary search for the index with largest value smaller than target u distance
|
172
|
+
|
173
|
+
let low = 0, high = il - 1, comparison;
|
174
|
+
|
175
|
+
while (low <= high) {
|
176
|
+
|
177
|
+
i = Math.floor(low + (high - low) / 2); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
|
178
|
+
|
179
|
+
comparison = arcLengths[i] - targetArcLength;
|
180
|
+
|
181
|
+
if (comparison < 0) {
|
182
|
+
|
183
|
+
low = i + 1;
|
184
|
+
|
185
|
+
} else if (comparison > 0) {
|
186
|
+
|
187
|
+
high = i - 1;
|
188
|
+
|
189
|
+
} else {
|
190
|
+
|
191
|
+
high = i;
|
192
|
+
break;
|
193
|
+
|
194
|
+
// DONE
|
195
|
+
|
196
|
+
}
|
197
|
+
|
198
|
+
}
|
199
|
+
|
200
|
+
i = high;
|
201
|
+
|
202
|
+
if (arcLengths[i] === targetArcLength) {
|
203
|
+
|
204
|
+
return i / (il - 1);
|
205
|
+
|
206
|
+
}
|
207
|
+
|
208
|
+
// we could get finer grain at lengths, or use simple interpolation between two points
|
209
|
+
|
210
|
+
const lengthBefore = arcLengths[i];
|
211
|
+
const lengthAfter = arcLengths[i + 1];
|
212
|
+
|
213
|
+
const segmentLength = lengthAfter - lengthBefore;
|
214
|
+
|
215
|
+
// determine where we are between the 'before' and 'after' points
|
216
|
+
|
217
|
+
const segmentFraction = (targetArcLength - lengthBefore) / segmentLength;
|
218
|
+
|
219
|
+
// add that fractional amount to t
|
220
|
+
|
221
|
+
const t = (i + segmentFraction) / (il - 1);
|
222
|
+
|
223
|
+
return t;
|
224
|
+
|
225
|
+
}
|
226
|
+
|
227
|
+
// Returns a unit vector tangent at t
|
228
|
+
// In case any sub curve does not implement its tangent derivation,
|
229
|
+
// 2 points a small delta apart will be used to find its gradient
|
230
|
+
// which seems to give a reasonable approximation
|
231
|
+
|
232
|
+
// getTangent(t, optionalTarget) {
|
233
|
+
|
234
|
+
// const delta = 0.0001;
|
235
|
+
// let t1 = t - delta;
|
236
|
+
// let t2 = t + delta;
|
237
|
+
|
238
|
+
// // Capping in case of danger
|
239
|
+
|
240
|
+
// if (t1 < 0) t1 = 0;
|
241
|
+
// if (t2 > 1) t2 = 1;
|
242
|
+
|
243
|
+
// const pt1 = this.getPoint(t1);
|
244
|
+
// const pt2 = this.getPoint(t2);
|
245
|
+
|
246
|
+
// const tangent = optionalTarget || ((pt1.isVector2) ? new Vector2() : new Vector3());
|
247
|
+
|
248
|
+
// tangent.copy(pt2).sub(pt1).normalize();
|
249
|
+
|
250
|
+
// return tangent;
|
251
|
+
|
252
|
+
// }
|
253
|
+
|
254
|
+
// getTangentAt(u, optionalTarget) {
|
255
|
+
|
256
|
+
// const t = this.getUtoTmapping(u);
|
257
|
+
// return this.getTangent(t, optionalTarget);
|
258
|
+
|
259
|
+
// }
|
260
|
+
|
261
|
+
// computeFrenetFrames(segments, closed) {
|
262
|
+
|
263
|
+
// // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
|
264
|
+
|
265
|
+
// const normal = new Vector3();
|
266
|
+
|
267
|
+
// const tangents = [];
|
268
|
+
// const normals = [];
|
269
|
+
// const binormals = [];
|
270
|
+
|
271
|
+
// const vec = new Vector3();
|
272
|
+
// const mat = new Matrix4();
|
273
|
+
|
274
|
+
// // compute the tangent vectors for each segment on the curve
|
275
|
+
|
276
|
+
// for (let i = 0; i <= segments; i++) {
|
277
|
+
|
278
|
+
// const u = i / segments;
|
279
|
+
|
280
|
+
// tangents[i] = this.getTangentAt(u, new Vector3());
|
281
|
+
|
282
|
+
// }
|
283
|
+
|
284
|
+
// // select an initial normal vector perpendicular to the first tangent vector,
|
285
|
+
// // and in the direction of the minimum tangent xyz component
|
286
|
+
|
287
|
+
// normals[0] = new Vector3();
|
288
|
+
// binormals[0] = new Vector3();
|
289
|
+
// let min = Number.MAX_VALUE;
|
290
|
+
// const tx = Math.abs(tangents[0].x);
|
291
|
+
// const ty = Math.abs(tangents[0].y);
|
292
|
+
// const tz = Math.abs(tangents[0].z);
|
293
|
+
|
294
|
+
// if (tx <= min) {
|
295
|
+
|
296
|
+
// min = tx;
|
297
|
+
// normal.set(1, 0, 0);
|
298
|
+
|
299
|
+
// }
|
300
|
+
|
301
|
+
// if (ty <= min) {
|
302
|
+
|
303
|
+
// min = ty;
|
304
|
+
// normal.set(0, 1, 0);
|
305
|
+
|
306
|
+
// }
|
307
|
+
|
308
|
+
// if (tz <= min) {
|
309
|
+
|
310
|
+
// normal.set(0, 0, 1);
|
311
|
+
|
312
|
+
// }
|
313
|
+
|
314
|
+
// vec.crossVectors(tangents[0], normal).normalize();
|
315
|
+
|
316
|
+
// normals[0].crossVectors(tangents[0], vec);
|
317
|
+
// binormals[0].crossVectors(tangents[0], normals[0]);
|
318
|
+
|
319
|
+
// // compute the slowly-varying normal and binormal vectors for each segment on the curve
|
320
|
+
|
321
|
+
// for (let i = 1; i <= segments; i++) {
|
322
|
+
|
323
|
+
// normals[i] = normals[i - 1].clone();
|
324
|
+
|
325
|
+
// binormals[i] = binormals[i - 1].clone();
|
326
|
+
|
327
|
+
// vec.crossVectors(tangents[i - 1], tangents[i]);
|
328
|
+
|
329
|
+
// if (vec.length() > Number.EPSILON) {
|
330
|
+
|
331
|
+
// vec.normalize();
|
332
|
+
|
333
|
+
// const theta = Math.acos(MathUtils.clamp(tangents[i - 1].dot(tangents[i]), - 1, 1)); // clamp for floating pt errors
|
334
|
+
|
335
|
+
// normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta));
|
336
|
+
|
337
|
+
// }
|
338
|
+
|
339
|
+
// binormals[i].crossVectors(tangents[i], normals[i]);
|
340
|
+
|
341
|
+
// }
|
342
|
+
|
343
|
+
// // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
|
344
|
+
|
345
|
+
// if (closed === true) {
|
346
|
+
|
347
|
+
// let theta = Math.acos(MathUtils.clamp(normals[0].dot(normals[segments]), - 1, 1));
|
348
|
+
// theta /= segments;
|
349
|
+
|
350
|
+
// if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
|
351
|
+
|
352
|
+
// theta = - theta;
|
353
|
+
|
354
|
+
// }
|
355
|
+
|
356
|
+
// for (let i = 1; i <= segments; i++) {
|
357
|
+
|
358
|
+
// // twist a little...
|
359
|
+
// normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));
|
360
|
+
// binormals[i].crossVectors(tangents[i], normals[i]);
|
361
|
+
|
362
|
+
// }
|
363
|
+
|
364
|
+
// }
|
365
|
+
|
366
|
+
// return {
|
367
|
+
// tangents: tangents,
|
368
|
+
// normals: normals,
|
369
|
+
// binormals: binormals
|
370
|
+
// };
|
371
|
+
|
372
|
+
// }
|
373
|
+
|
374
|
+
// clone() {
|
375
|
+
|
376
|
+
// return new this.constructor().copy(this);
|
377
|
+
|
378
|
+
// }
|
379
|
+
|
380
|
+
// copy(source) {
|
381
|
+
|
382
|
+
// this.arcLengthDivisions = source.arcLengthDivisions;
|
383
|
+
|
384
|
+
// return this;
|
385
|
+
|
386
|
+
// }
|
387
|
+
|
388
|
+
// toJSON() {
|
389
|
+
|
390
|
+
// const data = {
|
391
|
+
// metadata: {
|
392
|
+
// version: 4.6,
|
393
|
+
// type: 'Curve',
|
394
|
+
// generator: 'Curve.toJSON'
|
395
|
+
// }
|
396
|
+
// };
|
397
|
+
|
398
|
+
// data.arcLengthDivisions = this.arcLengthDivisions;
|
399
|
+
// data.type = this.type;
|
400
|
+
|
401
|
+
// return data;
|
402
|
+
|
403
|
+
// }
|
404
|
+
|
405
|
+
// fromJSON(json) {
|
406
|
+
|
407
|
+
// this.arcLengthDivisions = json.arcLengthDivisions;
|
408
|
+
|
409
|
+
// return this;
|
410
|
+
|
411
|
+
// }
|
412
|
+
|
413
|
+
}
|
414
|
+
|
415
|
+
export { Curve };
|
@@ -0,0 +1,80 @@
|
|
1
|
+
/**
|
2
|
+
* // code copy from https://github.com/mrdoob/three.js/blob/dev/src/extras/core/Interpolations.js
|
3
|
+
* Bezier Curves formulas obtained from
|
4
|
+
* https://en.wikipedia.org/wiki/B%C3%A9zier_curve
|
5
|
+
*/
|
6
|
+
|
7
|
+
function CatmullRom(t, p0, p1, p2, p3) {
|
8
|
+
|
9
|
+
const v0 = (p2 - p0) * 0.5;
|
10
|
+
const v1 = (p3 - p1) * 0.5;
|
11
|
+
const t2 = t * t;
|
12
|
+
const t3 = t * t2;
|
13
|
+
return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
|
14
|
+
|
15
|
+
}
|
16
|
+
|
17
|
+
//
|
18
|
+
|
19
|
+
function QuadraticBezierP0(t, p) {
|
20
|
+
|
21
|
+
const k = 1 - t;
|
22
|
+
return k * k * p;
|
23
|
+
|
24
|
+
}
|
25
|
+
|
26
|
+
function QuadraticBezierP1(t, p) {
|
27
|
+
|
28
|
+
return 2 * (1 - t) * t * p;
|
29
|
+
|
30
|
+
}
|
31
|
+
|
32
|
+
function QuadraticBezierP2(t, p) {
|
33
|
+
|
34
|
+
return t * t * p;
|
35
|
+
|
36
|
+
}
|
37
|
+
|
38
|
+
function QuadraticBezier(t, p0, p1, p2) {
|
39
|
+
|
40
|
+
return QuadraticBezierP0(t, p0) + QuadraticBezierP1(t, p1) +
|
41
|
+
QuadraticBezierP2(t, p2);
|
42
|
+
|
43
|
+
}
|
44
|
+
|
45
|
+
//
|
46
|
+
|
47
|
+
function CubicBezierP0(t, p) {
|
48
|
+
|
49
|
+
const k = 1 - t;
|
50
|
+
return k * k * k * p;
|
51
|
+
|
52
|
+
}
|
53
|
+
|
54
|
+
function CubicBezierP1(t, p) {
|
55
|
+
|
56
|
+
const k = 1 - t;
|
57
|
+
return 3 * k * k * t * p;
|
58
|
+
|
59
|
+
}
|
60
|
+
|
61
|
+
function CubicBezierP2(t, p) {
|
62
|
+
|
63
|
+
return 3 * (1 - t) * t * t * p;
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
function CubicBezierP3(t, p) {
|
68
|
+
|
69
|
+
return t * t * t * p;
|
70
|
+
|
71
|
+
}
|
72
|
+
|
73
|
+
function CubicBezier(t, p0, p1, p2, p3) {
|
74
|
+
|
75
|
+
return CubicBezierP0(t, p0) + CubicBezierP1(t, p1) + CubicBezierP2(t, p2) +
|
76
|
+
CubicBezierP3(t, p3);
|
77
|
+
|
78
|
+
}
|
79
|
+
|
80
|
+
export { CatmullRom, QuadraticBezier, CubicBezier };
|