@ue-too/curve 0.9.5 → 0.10.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/README.md +472 -4
- package/b-curve.d.ts +86 -0
- package/composite-curve.d.ts +16 -0
- package/index.d.ts +96 -0
- package/index.js +2 -1590
- package/index.js.map +6 -6
- package/line.d.ts +29 -0
- package/package.json +2 -2
- package/path.d.ts +4 -0
package/README.md
CHANGED
|
@@ -1,5 +1,473 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ue-too/curve
|
|
2
2
|
|
|
3
|
-
This is
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
This is a library that basically follows the algorithms in Pomax's superb [Primer on Bezier Curves](https://pomax.github.io/bezierinfo/) by Pomax. Of course, with my own interpretations on the inputs and outputs.
|
|
4
|
+
|
|
5
|
+
Bezier curve and geometric path library for TypeScript canvas applications.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@ue-too/curve)
|
|
8
|
+
[](https://github.com/ue-too/ue-too/blob/main/LICENSE.txt)
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
`@ue-too/curve` provides comprehensive tools for working with Bezier curves, lines, and composite paths. Inspired by Pomax's [Primer on Bezier Curves](https://pomax.github.io/bezierinfo/), this library includes advanced features like curve intersection detection, offset curves, arc fitting, and arc-length parameterization.
|
|
13
|
+
|
|
14
|
+
### Key Features
|
|
15
|
+
|
|
16
|
+
- **Bezier Curves**: Quadratic and cubic Bezier curves with full geometric operations
|
|
17
|
+
- **Curve Evaluation**: Evaluate curves at any parameter `t` with caching for performance
|
|
18
|
+
- **Arc-Length Parameterization**: Uniform spacing along curves for animations and path following
|
|
19
|
+
- **Intersection Detection**: Self-intersections, curve-to-curve, curve-to-line, and curve-to-circle
|
|
20
|
+
- **Geometric Queries**: Project points, find closest points, calculate bounding boxes
|
|
21
|
+
- **Advanced Operations**: Split curves, offset curves, reduce complexity, fit arcs
|
|
22
|
+
- **Composite Curves**: Multi-segment curves with control points and tangent handles
|
|
23
|
+
- **Paths**: Sequential line segment paths with utilities
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Using Bun:
|
|
28
|
+
```bash
|
|
29
|
+
bun add @ue-too/curve
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Using npm:
|
|
33
|
+
```bash
|
|
34
|
+
npm install @ue-too/curve
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
Here's a simple example creating and evaluating a Bezier curve:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { BCurve } from '@ue-too/curve';
|
|
43
|
+
|
|
44
|
+
// Create a quadratic Bezier curve
|
|
45
|
+
const curve = new BCurve([
|
|
46
|
+
{ x: 0, y: 0 }, // Start point
|
|
47
|
+
{ x: 50, y: 100 }, // Control point
|
|
48
|
+
{ x: 100, y: 0 } // End point
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
// Evaluate at midpoint (t = 0.5)
|
|
52
|
+
const midpoint = curve.get(0.5);
|
|
53
|
+
console.log('Midpoint:', midpoint); // { x: 50, y: 50 }
|
|
54
|
+
|
|
55
|
+
// Get total arc length
|
|
56
|
+
console.log('Length:', curve.fullLength);
|
|
57
|
+
|
|
58
|
+
// Split curve at t = 0.5
|
|
59
|
+
const [left, right] = curve.splitIntoCurves(0.5);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Core Concepts
|
|
63
|
+
|
|
64
|
+
### Bezier Curves
|
|
65
|
+
|
|
66
|
+
Bezier curves are parametric curves defined by control points. This library supports:
|
|
67
|
+
|
|
68
|
+
- **Linear Bezier** (2 control points): Straight line
|
|
69
|
+
- **Quadratic Bezier** (3 control points): Simple curve with one control point
|
|
70
|
+
- **Cubic Bezier** (4 control points): Complex curve with two control points
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// Linear Bezier (line)
|
|
74
|
+
const line = new BCurve([
|
|
75
|
+
{ x: 0, y: 0 },
|
|
76
|
+
{ x: 100, y: 100 }
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
// Quadratic Bezier
|
|
80
|
+
const quadratic = new BCurve([
|
|
81
|
+
{ x: 0, y: 0 },
|
|
82
|
+
{ x: 50, y: 100 },
|
|
83
|
+
{ x: 100, y: 0 }
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
// Cubic Bezier
|
|
87
|
+
const cubic = new BCurve([
|
|
88
|
+
{ x: 0, y: 0 },
|
|
89
|
+
{ x: 33, y: 100 },
|
|
90
|
+
{ x: 66, y: 100 },
|
|
91
|
+
{ x: 100, y: 0 }
|
|
92
|
+
]);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Parameter `t`
|
|
96
|
+
|
|
97
|
+
Bezier curves are evaluated using a parameter `t` from 0.0 (start) to 1.0 (end):
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const start = curve.get(0); // Start point
|
|
101
|
+
const mid = curve.get(0.5); // Midpoint
|
|
102
|
+
const end = curve.get(1); // End point
|
|
103
|
+
const quarter = curve.get(0.25); // 25% along the curve
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Core APIs
|
|
107
|
+
|
|
108
|
+
### BCurve Class
|
|
109
|
+
|
|
110
|
+
Main Bezier curve class with extensive geometric operations.
|
|
111
|
+
|
|
112
|
+
**Constructor:**
|
|
113
|
+
```typescript
|
|
114
|
+
const curve = new BCurve(controlPoints: Point[]);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Curve Evaluation:**
|
|
118
|
+
- `get(t: number): Point` - Get point at parameter t
|
|
119
|
+
- `derivative(t: number): Point` - Get derivative vector at t
|
|
120
|
+
- `normal(t: number): Point` - Get normal vector at t
|
|
121
|
+
- `tangent(t: number): Point` - Get tangent vector at t
|
|
122
|
+
|
|
123
|
+
**Geometric Properties:**
|
|
124
|
+
- `fullLength: number` - Total arc length (cached)
|
|
125
|
+
- `bbox(): {x: {min: number, max: number}, y: {min: number, max: number}}` - Axis-aligned bounding box
|
|
126
|
+
- `extrema(): {x: number[], y: number[]}` - Find extrema (min/max) points
|
|
127
|
+
- `curvature(t: number): number` - Calculate curvature at t
|
|
128
|
+
|
|
129
|
+
**Curve Manipulation:**
|
|
130
|
+
- `splitIntoCurves(t: number): [BCurve, BCurve]` - Split into two curves at t
|
|
131
|
+
- `scale(factor: number, origin?: Point): BCurve` - Scale curve around origin
|
|
132
|
+
- `offset(distance: number): BCurve | BCurve[]` - Create offset (parallel) curve
|
|
133
|
+
|
|
134
|
+
**Intersection Detection:**
|
|
135
|
+
- `getCurveIntersections(other: BCurve): {selfT: number, otherT: number}[]` - Find curve-curve intersections
|
|
136
|
+
- `getLineIntersections(line: Line): number[]` - Find curve-line intersection points
|
|
137
|
+
- `getCircleIntersections(center: Point, radius: number): number[]` - Find curve-circle intersections
|
|
138
|
+
- `getSelfIntersections(): {t1: number, t2: number}[]` - Detect self-intersections
|
|
139
|
+
|
|
140
|
+
**Point Queries:**
|
|
141
|
+
- `project(point: Point): {t: number, point: Point, distance: number}` - Project point onto curve
|
|
142
|
+
- `closestPoint(point: Point): Point` - Find closest point on curve
|
|
143
|
+
|
|
144
|
+
**Arc-Length Functions:**
|
|
145
|
+
- `length(t: number): number` - Arc length from start to parameter t
|
|
146
|
+
- `parameter(length: number): number` - Find parameter t for a given arc length
|
|
147
|
+
|
|
148
|
+
### Line Class
|
|
149
|
+
|
|
150
|
+
Straight line segment utilities.
|
|
151
|
+
|
|
152
|
+
**Constructor:**
|
|
153
|
+
```typescript
|
|
154
|
+
const line = new Line(start: Point, end: Point);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Properties:**
|
|
158
|
+
- `start: Point` - Starting point
|
|
159
|
+
- `end: Point` - Ending point
|
|
160
|
+
- `length: number` - Line length
|
|
161
|
+
|
|
162
|
+
**Methods:**
|
|
163
|
+
- `get(t: number): Point` - Get point at parameter t (0-1)
|
|
164
|
+
- `intersects(other: Line): Point | null` - Find intersection point with another line
|
|
165
|
+
- `project(point: Point): {t: number, point: Point}` - Project point onto line
|
|
166
|
+
- `distanceToPoint(point: Point): number` - Distance from point to line
|
|
167
|
+
|
|
168
|
+
### CompositeBCurve Class
|
|
169
|
+
|
|
170
|
+
Composite curve made of multiple Bezier segments with control points and tangent handles.
|
|
171
|
+
|
|
172
|
+
**Constructor:**
|
|
173
|
+
```typescript
|
|
174
|
+
const composite = new CompositeBCurve(controlPoints: ControlPoint[]);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Control Point Structure:**
|
|
178
|
+
```typescript
|
|
179
|
+
type ControlPoint = {
|
|
180
|
+
point: Point; // Anchor point
|
|
181
|
+
leftHandle?: Point; // Left tangent handle
|
|
182
|
+
rightHandle?: Point; // Right tangent handle
|
|
183
|
+
};
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Path Class
|
|
187
|
+
|
|
188
|
+
Path composed of sequential line segments.
|
|
189
|
+
|
|
190
|
+
**Constructor:**
|
|
191
|
+
```typescript
|
|
192
|
+
const path = new Path(points: Point[]);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Methods:**
|
|
196
|
+
- `get(index: number): Line` - Get line segment at index
|
|
197
|
+
- `length(): number` - Total path length
|
|
198
|
+
- `bbox(): {x: {min, max}, y: {min, max}}` - Bounding box
|
|
199
|
+
|
|
200
|
+
## Common Use Cases
|
|
201
|
+
|
|
202
|
+
### Draw a Curve on Canvas
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { BCurve } from '@ue-too/curve';
|
|
206
|
+
|
|
207
|
+
const curve = new BCurve([
|
|
208
|
+
{ x: 50, y: 200 },
|
|
209
|
+
{ x: 150, y: 50 },
|
|
210
|
+
{ x: 250, y: 200 }
|
|
211
|
+
]);
|
|
212
|
+
|
|
213
|
+
// Draw using canvas API
|
|
214
|
+
ctx.beginPath();
|
|
215
|
+
ctx.moveTo(curve.points[0].x, curve.points[0].y);
|
|
216
|
+
|
|
217
|
+
if (curve.points.length === 3) {
|
|
218
|
+
// Quadratic curve
|
|
219
|
+
ctx.quadraticCurveTo(
|
|
220
|
+
curve.points[1].x, curve.points[1].y,
|
|
221
|
+
curve.points[2].x, curve.points[2].y
|
|
222
|
+
);
|
|
223
|
+
} else if (curve.points.length === 4) {
|
|
224
|
+
// Cubic curve
|
|
225
|
+
ctx.bezierCurveTo(
|
|
226
|
+
curve.points[1].x, curve.points[1].y,
|
|
227
|
+
curve.points[2].x, curve.points[2].y,
|
|
228
|
+
curve.points[3].x, curve.points[3].y
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
ctx.stroke();
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Animate Object Along Curve
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { BCurve } from '@ue-too/curve';
|
|
239
|
+
|
|
240
|
+
const curve = new BCurve([
|
|
241
|
+
{ x: 0, y: 100 },
|
|
242
|
+
{ x: 100, y: 0 },
|
|
243
|
+
{ x: 200, y: 100 }
|
|
244
|
+
]);
|
|
245
|
+
|
|
246
|
+
let t = 0;
|
|
247
|
+
|
|
248
|
+
function animate() {
|
|
249
|
+
t += 0.01;
|
|
250
|
+
if (t > 1) t = 0;
|
|
251
|
+
|
|
252
|
+
const position = curve.get(t);
|
|
253
|
+
const tangent = curve.tangent(t);
|
|
254
|
+
|
|
255
|
+
// Draw object at position with rotation from tangent
|
|
256
|
+
const angle = Math.atan2(tangent.y, tangent.x);
|
|
257
|
+
drawSprite(position.x, position.y, angle);
|
|
258
|
+
|
|
259
|
+
requestAnimationFrame(animate);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Uniform Spacing with Arc-Length Parameterization
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { BCurve } from '@ue-too/curve';
|
|
267
|
+
|
|
268
|
+
const curve = new BCurve([
|
|
269
|
+
{ x: 0, y: 0 },
|
|
270
|
+
{ x: 100, y: 100 },
|
|
271
|
+
{ x: 200, y: 0 }
|
|
272
|
+
]);
|
|
273
|
+
|
|
274
|
+
const totalLength = curve.fullLength;
|
|
275
|
+
const spacing = 10; // Pixels between points
|
|
276
|
+
const numPoints = Math.floor(totalLength / spacing);
|
|
277
|
+
|
|
278
|
+
// Place points uniformly along the curve
|
|
279
|
+
for (let i = 0; i <= numPoints; i++) {
|
|
280
|
+
const arcLength = i * spacing;
|
|
281
|
+
const t = curve.parameter(arcLength); // Convert arc-length to parameter
|
|
282
|
+
const point = curve.get(t);
|
|
283
|
+
|
|
284
|
+
drawPoint(point.x, point.y);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Detect Curve Intersections
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { BCurve } from '@ue-too/curve';
|
|
292
|
+
|
|
293
|
+
const curve1 = new BCurve([
|
|
294
|
+
{ x: 0, y: 50 },
|
|
295
|
+
{ x: 100, y: 150 },
|
|
296
|
+
{ x: 200, y: 50 }
|
|
297
|
+
]);
|
|
298
|
+
|
|
299
|
+
const curve2 = new BCurve([
|
|
300
|
+
{ x: 0, y: 100 },
|
|
301
|
+
{ x: 100, y: 0 },
|
|
302
|
+
{ x: 200, y: 100 }
|
|
303
|
+
]);
|
|
304
|
+
|
|
305
|
+
const intersections = curve1.getCurveIntersections(curve2);
|
|
306
|
+
|
|
307
|
+
intersections.forEach(({ selfT, otherT }) => {
|
|
308
|
+
const point1 = curve1.get(selfT);
|
|
309
|
+
const point2 = curve2.get(otherT);
|
|
310
|
+
|
|
311
|
+
console.log('Intersection at:', point1);
|
|
312
|
+
// point1 and point2 should be very close (within numerical precision)
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Find Closest Point on Curve
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
import { BCurve } from '@ue-too/curve';
|
|
320
|
+
|
|
321
|
+
const curve = new BCurve([
|
|
322
|
+
{ x: 0, y: 0 },
|
|
323
|
+
{ x: 50, y: 100 },
|
|
324
|
+
{ x: 100, y: 0 }
|
|
325
|
+
]);
|
|
326
|
+
|
|
327
|
+
const mousePosition = { x: 60, y: 40 };
|
|
328
|
+
const { t, point, distance } = curve.project(mousePosition);
|
|
329
|
+
|
|
330
|
+
console.log('Closest point:', point);
|
|
331
|
+
console.log('At parameter:', t);
|
|
332
|
+
console.log('Distance:', distance);
|
|
333
|
+
|
|
334
|
+
// Snap mouse to curve
|
|
335
|
+
if (distance < 10) {
|
|
336
|
+
snapToCurve(point);
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Create Offset Curve
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { BCurve } from '@ue-too/curve';
|
|
344
|
+
|
|
345
|
+
const curve = new BCurve([
|
|
346
|
+
{ x: 0, y: 100 },
|
|
347
|
+
{ x: 100, y: 0 },
|
|
348
|
+
{ x: 200, y: 100 }
|
|
349
|
+
]);
|
|
350
|
+
|
|
351
|
+
// Create curve offset by 20 pixels
|
|
352
|
+
const offsetCurves = curve.offset(20);
|
|
353
|
+
|
|
354
|
+
// Offset may produce multiple curve segments
|
|
355
|
+
offsetCurves.forEach(offsetCurve => {
|
|
356
|
+
drawCurve(offsetCurve);
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Split Curve at Point
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
import { BCurve } from '@ue-too/curve';
|
|
364
|
+
|
|
365
|
+
const curve = new BCurve([
|
|
366
|
+
{ x: 0, y: 0 },
|
|
367
|
+
{ x: 50, y: 100 },
|
|
368
|
+
{ x: 100, y: 0 }
|
|
369
|
+
]);
|
|
370
|
+
|
|
371
|
+
// Split at 30% along the curve
|
|
372
|
+
const [leftPart, rightPart] = curve.splitIntoCurves(0.3);
|
|
373
|
+
|
|
374
|
+
// Draw each part in different colors
|
|
375
|
+
drawCurve(leftPart, 'red');
|
|
376
|
+
drawCurve(rightPart, 'blue');
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Bounding Box for Culling
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
import { BCurve } from '@ue-too/curve';
|
|
383
|
+
|
|
384
|
+
const curve = new BCurve([
|
|
385
|
+
{ x: 10, y: 20 },
|
|
386
|
+
{ x: 150, y: 200 },
|
|
387
|
+
{ x: 300, y: 50 }
|
|
388
|
+
]);
|
|
389
|
+
|
|
390
|
+
const bbox = curve.bbox();
|
|
391
|
+
|
|
392
|
+
// Check if curve is visible in viewport
|
|
393
|
+
const isVisible = (
|
|
394
|
+
bbox.x.max >= viewport.left &&
|
|
395
|
+
bbox.x.min <= viewport.right &&
|
|
396
|
+
bbox.y.max >= viewport.top &&
|
|
397
|
+
bbox.y.min <= viewport.bottom
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
if (isVisible) {
|
|
401
|
+
drawCurve(curve);
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## API Reference
|
|
406
|
+
|
|
407
|
+
For complete API documentation with detailed type information, see the [TypeDoc-generated documentation](../../docs/curve).
|
|
408
|
+
|
|
409
|
+
## TypeScript Support
|
|
410
|
+
|
|
411
|
+
This package is written in TypeScript with complete type definitions:
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
import { BCurve, Line, Point } from '@ue-too/curve';
|
|
415
|
+
|
|
416
|
+
// Points are fully typed
|
|
417
|
+
const point: Point = { x: 10, y: 20 };
|
|
418
|
+
|
|
419
|
+
// Curves are generic over control point count
|
|
420
|
+
const quadratic: BCurve = new BCurve([
|
|
421
|
+
{ x: 0, y: 0 },
|
|
422
|
+
{ x: 50, y: 100 },
|
|
423
|
+
{ x: 100, y: 0 }
|
|
424
|
+
]);
|
|
425
|
+
|
|
426
|
+
// Intersection results are typed
|
|
427
|
+
const intersections: { selfT: number; otherT: number }[] =
|
|
428
|
+
curve1.getCurveIntersections(curve2);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Design Philosophy
|
|
432
|
+
|
|
433
|
+
This library follows these principles:
|
|
434
|
+
|
|
435
|
+
- **Geometric correctness**: Implements algorithms from academic literature
|
|
436
|
+
- **Performance**: Caches expensive calculations (arc-length tables)
|
|
437
|
+
- **Type safety**: Leverages TypeScript for compile-time guarantees
|
|
438
|
+
- **Composability**: Build complex curves from simple primitives
|
|
439
|
+
- **Practical**: Focused on real-world canvas and graphics use cases
|
|
440
|
+
|
|
441
|
+
## Performance Considerations
|
|
442
|
+
|
|
443
|
+
- **Arc-length caching**: First call to `fullLength` builds a lookup table, subsequent calls are O(1)
|
|
444
|
+
- **Intersection detection**: Uses recursive subdivision (can be expensive for complex curves)
|
|
445
|
+
- **Curve splitting**: Fast operation using De Casteljau's algorithm
|
|
446
|
+
- **Offset curves**: Computationally expensive, may produce multiple segments
|
|
447
|
+
|
|
448
|
+
**Performance Tips:**
|
|
449
|
+
- Cache `fullLength` results if curves don't change
|
|
450
|
+
- Use bounding box checks before expensive intersection tests
|
|
451
|
+
- Reduce curve complexity with `reduce()` for long curves
|
|
452
|
+
- Split curves into segments for faster intersection detection
|
|
453
|
+
|
|
454
|
+
## Related Packages
|
|
455
|
+
|
|
456
|
+
- **[@ue-too/math](../math)**: Vector operations for point manipulation
|
|
457
|
+
- **[@ue-too/animate](../animate)**: Animate objects along curves
|
|
458
|
+
- **[@ue-too/border](../border)**: Border rendering that can use curves
|
|
459
|
+
- **[@ue-too/board](../board)**: Canvas board for rendering curves
|
|
460
|
+
|
|
461
|
+
## Further Reading
|
|
462
|
+
|
|
463
|
+
- [A Primer on Bezier Curves](https://pomax.github.io/bezierinfo/) by Pomax - Comprehensive guide this library is based on
|
|
464
|
+
- [bezier-js](https://github.com/Pomax/bezierjs) - Reference implementation in JavaScript
|
|
465
|
+
- [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm) - Curve evaluation and splitting
|
|
466
|
+
|
|
467
|
+
## License
|
|
468
|
+
|
|
469
|
+
MIT
|
|
470
|
+
|
|
471
|
+
## Repository
|
|
472
|
+
|
|
473
|
+
[https://github.com/ue-too/ue-too](https://github.com/ue-too/ue-too)
|
package/b-curve.d.ts
CHANGED
|
@@ -14,6 +14,52 @@ type AdvanceAtWithLengthAfterCurveRes = {
|
|
|
14
14
|
};
|
|
15
15
|
type AdvanceAtTWithLengthOutofCurveRes = AdvanceAtWithLengthBeforeCurveRes | AdvanceAtWithLengthAfterCurveRes;
|
|
16
16
|
type AdvanceAtTWithLengthRes = AdvanceAtTWithLengthWithinCurveRes | AdvanceAtTWithLengthOutofCurveRes;
|
|
17
|
+
/**
|
|
18
|
+
* Bezier curve class supporting quadratic (3 points) and cubic (4 points) curves.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* BCurve provides a comprehensive implementation of Bezier curves with:
|
|
22
|
+
* - Curve evaluation at any parameter t (0 to 1)
|
|
23
|
+
* - Arc-length calculation with caching for performance
|
|
24
|
+
* - Curve splitting and subdivision
|
|
25
|
+
* - Geometric queries (projection, intersection, extrema)
|
|
26
|
+
* - Advanced operations (offset, arc fitting, curvature)
|
|
27
|
+
*
|
|
28
|
+
* ## Performance Optimizations
|
|
29
|
+
* - Optimized formulas for quadratic and cubic curves
|
|
30
|
+
* - Arc-length caching to avoid recomputation
|
|
31
|
+
* - Lazy computation of lookup tables (LUT)
|
|
32
|
+
* - Gauss-Legendre quadrature for arc-length calculation
|
|
33
|
+
*
|
|
34
|
+
* ## Coordinate System
|
|
35
|
+
* - Parameter t ranges from 0 (start) to 1 (end)
|
|
36
|
+
* - Points use {x, y} coordinates
|
|
37
|
+
* - Supports 2D curves (z-coordinate optional but not used)
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* Create and evaluate a cubic Bezier curve
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const curve = new BCurve([
|
|
43
|
+
* { x: 0, y: 0 }, // Start point
|
|
44
|
+
* { x: 33, y: 100 }, // Control point 1
|
|
45
|
+
* { x: 66, y: 100 }, // Control point 2
|
|
46
|
+
* { x: 100, y: 0 } // End point
|
|
47
|
+
* ]);
|
|
48
|
+
*
|
|
49
|
+
* // Evaluate at different positions
|
|
50
|
+
* const start = curve.get(0); // { x: 0, y: 0 }
|
|
51
|
+
* const mid = curve.get(0.5); // Midpoint
|
|
52
|
+
* const end = curve.get(1); // { x: 100, y: 0 }
|
|
53
|
+
*
|
|
54
|
+
* // Get curve length
|
|
55
|
+
* console.log('Length:', curve.fullLength);
|
|
56
|
+
*
|
|
57
|
+
* // Get derivative (tangent vector)
|
|
58
|
+
* const tangent = curve.derivative(0.5);
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @category Core
|
|
62
|
+
*/
|
|
17
63
|
export declare class BCurve {
|
|
18
64
|
private controlPoints;
|
|
19
65
|
private dControlPoints;
|
|
@@ -148,7 +194,15 @@ export declare class BCurve {
|
|
|
148
194
|
direction: Point;
|
|
149
195
|
};
|
|
150
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Reduces a Bezier curve into simpler segments.
|
|
199
|
+
* @category Utilities
|
|
200
|
+
*/
|
|
151
201
|
export declare function reduce(curve: BCurve): BCurve[];
|
|
202
|
+
/**
|
|
203
|
+
* Creates offset curves at a specified distance from the original curve.
|
|
204
|
+
* @category Utilities
|
|
205
|
+
*/
|
|
152
206
|
export declare function offset(curve: BCurve, t: number): BCurve[];
|
|
153
207
|
export declare function offset(curve: BCurve, t: number, d: number): {
|
|
154
208
|
c: Point;
|
|
@@ -156,15 +210,31 @@ export declare function offset(curve: BCurve, t: number, d: number): {
|
|
|
156
210
|
x: number;
|
|
157
211
|
y: number;
|
|
158
212
|
};
|
|
213
|
+
/**
|
|
214
|
+
* Alternative offset implementation using LUT-based approach.
|
|
215
|
+
* @category Utilities
|
|
216
|
+
*/
|
|
159
217
|
export declare function offset2(curve: BCurve, d: number): Point[];
|
|
218
|
+
/**
|
|
219
|
+
* Error thrown when t-value is out of valid range [0, 1].
|
|
220
|
+
* @category Types
|
|
221
|
+
*/
|
|
160
222
|
export declare class TValOutofBoundError extends Error {
|
|
161
223
|
constructor(message: string);
|
|
162
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* 2D/3D point type.
|
|
227
|
+
* @category Types
|
|
228
|
+
*/
|
|
163
229
|
export type Point = {
|
|
164
230
|
x: number;
|
|
165
231
|
y: number;
|
|
166
232
|
z?: number;
|
|
167
233
|
};
|
|
234
|
+
/**
|
|
235
|
+
* Tests if two axis-aligned bounding boxes intersect.
|
|
236
|
+
* @category Utilities
|
|
237
|
+
*/
|
|
168
238
|
export declare function AABBIntersects(AABB1: {
|
|
169
239
|
min: Point;
|
|
170
240
|
max: Point;
|
|
@@ -172,15 +242,31 @@ export declare function AABBIntersects(AABB1: {
|
|
|
172
242
|
min: Point;
|
|
173
243
|
max: Point;
|
|
174
244
|
}): boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Checks if two numbers are approximately equal within a precision threshold.
|
|
247
|
+
* @category Utilities
|
|
248
|
+
*/
|
|
175
249
|
export declare function approximately(a: number, b: number, precision?: number): boolean;
|
|
176
250
|
export declare function cuberoot2(v: number): number;
|
|
177
251
|
export declare function accept(t: number): boolean;
|
|
178
252
|
export declare function getCubicRoots(pa: number, pb: number, pc: number, pd: number): number[];
|
|
253
|
+
/**
|
|
254
|
+
* Finds all intersection points between two Bezier curves.
|
|
255
|
+
* @category Utilities
|
|
256
|
+
*/
|
|
179
257
|
export declare function getIntersectionsBetweenCurves(curve: BCurve, curve2: BCurve, deduplicationTolerance?: number): {
|
|
180
258
|
selfT: number;
|
|
181
259
|
otherT: number;
|
|
182
260
|
}[];
|
|
261
|
+
/**
|
|
262
|
+
* Solves cubic equations.
|
|
263
|
+
* @category Utilities
|
|
264
|
+
*/
|
|
183
265
|
export declare function solveCubic(a: number, b: number, c: number, d: number): number[];
|
|
184
266
|
export declare function cuberoot(x: number): number;
|
|
267
|
+
/**
|
|
268
|
+
* Computes point on curve using De Casteljau's algorithm.
|
|
269
|
+
* @category Utilities
|
|
270
|
+
*/
|
|
185
271
|
export declare function computeWithControlPoints(tVal: number, controlPoints: Point[]): Point;
|
|
186
272
|
export {};
|
package/composite-curve.d.ts
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { Point } from "@ue-too/math";
|
|
2
|
+
/**
|
|
3
|
+
* Handle type for Bezier curve control points.
|
|
4
|
+
* @category Types
|
|
5
|
+
*/
|
|
2
6
|
export type HandleType = "ALIGNED" | "VECTOR" | "FREE";
|
|
7
|
+
/**
|
|
8
|
+
* Handle point with position and type.
|
|
9
|
+
* @category Types
|
|
10
|
+
*/
|
|
3
11
|
export type HandlePoint = {
|
|
4
12
|
position: Point;
|
|
5
13
|
type: HandleType;
|
|
6
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Control point with left and right handles for composite Bezier curves.
|
|
17
|
+
* @category Core
|
|
18
|
+
*/
|
|
7
19
|
export declare class ControlPoint {
|
|
8
20
|
private position;
|
|
9
21
|
private leftHandle;
|
|
@@ -22,6 +34,10 @@ export declare class ControlPoint {
|
|
|
22
34
|
getLeftHandle(): HandlePoint;
|
|
23
35
|
getRightHandle(): HandlePoint;
|
|
24
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Composite Bezier curve made of multiple control points with handles.
|
|
39
|
+
* @category Core
|
|
40
|
+
*/
|
|
25
41
|
export declare class CompositeBCurve {
|
|
26
42
|
private controlPoints;
|
|
27
43
|
constructor(controlPoints?: ControlPoint[]);
|