@triforge/curve-core 0.1.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/core/BaseCurve.d.ts +44 -0
- package/dist/core/BaseCurve.d.ts.map +1 -0
- package/dist/core/BaseCurve.js +83 -0
- package/dist/core/BaseCurve.js.map +1 -0
- package/dist/core/BezierCurve.d.ts +63 -0
- package/dist/core/BezierCurve.d.ts.map +1 -0
- package/dist/core/BezierCurve.js +218 -0
- package/dist/core/BezierCurve.js.map +1 -0
- package/dist/core/CatmullRomCurve.d.ts +28 -0
- package/dist/core/CatmullRomCurve.d.ts.map +1 -0
- package/dist/core/CatmullRomCurve.js +100 -0
- package/dist/core/CatmullRomCurve.js.map +1 -0
- package/dist/core/NURBSCurve.d.ts +42 -0
- package/dist/core/NURBSCurve.d.ts.map +1 -0
- package/dist/core/NURBSCurve.js +103 -0
- package/dist/core/NURBSCurve.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/operations/CurveBevel.d.ts +43 -0
- package/dist/operations/CurveBevel.d.ts.map +1 -0
- package/dist/operations/CurveBevel.js +140 -0
- package/dist/operations/CurveBevel.js.map +1 -0
- package/dist/operations/CurveLine.d.ts +19 -0
- package/dist/operations/CurveLine.d.ts.map +1 -0
- package/dist/operations/CurveLine.js +25 -0
- package/dist/operations/CurveLine.js.map +1 -0
- package/dist/operations/CurveTube.d.ts +36 -0
- package/dist/operations/CurveTube.d.ts.map +1 -0
- package/dist/operations/CurveTube.js +141 -0
- package/dist/operations/CurveTube.js.map +1 -0
- package/dist/operations/PathFollow.d.ts +53 -0
- package/dist/operations/PathFollow.d.ts.map +1 -0
- package/dist/operations/PathFollow.js +84 -0
- package/dist/operations/PathFollow.js.map +1 -0
- package/dist/utils/frames.d.ts +30 -0
- package/dist/utils/frames.d.ts.map +1 -0
- package/dist/utils/frames.js +77 -0
- package/dist/utils/frames.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Vector3 } from 'three';
|
|
2
|
+
import { BaseCurve } from './BaseCurve.js';
|
|
3
|
+
/**
|
|
4
|
+
* NURBSCurve — Non-Uniform Rational B-Spline.
|
|
5
|
+
* Blender: NURBS spline type.
|
|
6
|
+
*
|
|
7
|
+
* Supports arbitrary degree (order = degree + 1), non-uniform knots, and per-point weights.
|
|
8
|
+
* A weight > 1 pulls the curve toward that control point; weight = 1 is uniform (B-spline).
|
|
9
|
+
* Circle arcs require weight = cos(θ/2) where θ is the arc angle.
|
|
10
|
+
*/
|
|
11
|
+
export class NURBSCurve extends BaseCurve {
|
|
12
|
+
constructor(points, opts = {}) {
|
|
13
|
+
super();
|
|
14
|
+
this.curveType = 'NURBSCurve';
|
|
15
|
+
this.parameters = {};
|
|
16
|
+
if (points.length < 2)
|
|
17
|
+
throw new Error('NURBSCurve requires at least 2 control points');
|
|
18
|
+
this._points = points;
|
|
19
|
+
this.order = Math.min(opts.order ?? 4, points.length); // order must be ≤ n
|
|
20
|
+
this._weights = opts.weights ?? points.map(() => 1);
|
|
21
|
+
this.closed = opts.closed ?? false;
|
|
22
|
+
this._knots = opts.knots ?? buildOpenUniformKnots(points.length, this.order);
|
|
23
|
+
}
|
|
24
|
+
get points() { return this._points; }
|
|
25
|
+
get weights() { return this._weights; }
|
|
26
|
+
get knots() { return this._knots; }
|
|
27
|
+
getPoint(t, target = new Vector3()) {
|
|
28
|
+
t = Math.max(0, Math.min(1, t));
|
|
29
|
+
const n = this._points.length;
|
|
30
|
+
const p = this.order - 1; // degree
|
|
31
|
+
const knots = this._knots;
|
|
32
|
+
// Map t to knot range [knots[p], knots[n]]
|
|
33
|
+
const lo = knots[p], hi = knots[n];
|
|
34
|
+
const u = lo + t * (hi - lo);
|
|
35
|
+
let wx = 0, wy = 0, wz = 0, ww = 0;
|
|
36
|
+
for (let i = 0; i < n; i++) {
|
|
37
|
+
const b = basisFunction(i, p, u, knots, hi);
|
|
38
|
+
const w = this._weights[i] * b;
|
|
39
|
+
wx += this._points[i].x * w;
|
|
40
|
+
wy += this._points[i].y * w;
|
|
41
|
+
wz += this._points[i].z * w;
|
|
42
|
+
ww += w;
|
|
43
|
+
}
|
|
44
|
+
if (ww === 0)
|
|
45
|
+
return target.copy(this._points[0]);
|
|
46
|
+
return target.set(wx / ww, wy / ww, wz / ww);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Cox-de Boor recursion for B-spline basis function N_{i,p}(u). */
|
|
50
|
+
function basisFunction(i, p, u, knots, uMax) {
|
|
51
|
+
if (p === 0) {
|
|
52
|
+
// Special case: at the last knot value, the last basis function = 1
|
|
53
|
+
if (u === uMax)
|
|
54
|
+
return (knots[i + 1] === uMax) ? 1 : 0;
|
|
55
|
+
return (u >= knots[i] && u < knots[i + 1]) ? 1 : 0;
|
|
56
|
+
}
|
|
57
|
+
const left = knots[i + p] - knots[i];
|
|
58
|
+
const right = knots[i + p + 1] - knots[i + 1];
|
|
59
|
+
let result = 0;
|
|
60
|
+
if (left > 0)
|
|
61
|
+
result += ((u - knots[i]) / left) * basisFunction(i, p - 1, u, knots, uMax);
|
|
62
|
+
if (right > 0)
|
|
63
|
+
result += ((knots[i + p + 1] - u) / right) * basisFunction(i + 1, p - 1, u, knots, uMax);
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
/** Open uniform knot vector for n control points and given order (clamped at both ends). */
|
|
67
|
+
export function buildOpenUniformKnots(n, order) {
|
|
68
|
+
const p = order - 1;
|
|
69
|
+
const total = n + order;
|
|
70
|
+
const knots = [];
|
|
71
|
+
for (let i = 0; i < total; i++) {
|
|
72
|
+
if (i < order)
|
|
73
|
+
knots.push(0);
|
|
74
|
+
else if (i >= n)
|
|
75
|
+
knots.push(n - p);
|
|
76
|
+
else
|
|
77
|
+
knots.push(i - p);
|
|
78
|
+
}
|
|
79
|
+
return knots;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build a NURBS circle in XY plane with given radius.
|
|
83
|
+
* Uses 9 control points with cos(45°) weights for exact circular arcs.
|
|
84
|
+
*/
|
|
85
|
+
export function buildNURBSCircle(radius = 1) {
|
|
86
|
+
const w = Math.SQRT1_2; // cos(45°) = 1/√2
|
|
87
|
+
const r = radius;
|
|
88
|
+
const points = [
|
|
89
|
+
new Vector3(r, 0, 0),
|
|
90
|
+
new Vector3(r, r, 0),
|
|
91
|
+
new Vector3(0, r, 0),
|
|
92
|
+
new Vector3(-r, r, 0),
|
|
93
|
+
new Vector3(-r, 0, 0),
|
|
94
|
+
new Vector3(-r, -r, 0),
|
|
95
|
+
new Vector3(0, -r, 0),
|
|
96
|
+
new Vector3(r, -r, 0),
|
|
97
|
+
new Vector3(r, 0, 0),
|
|
98
|
+
];
|
|
99
|
+
const weights = [1, w, 1, w, 1, w, 1, w, 1];
|
|
100
|
+
const knots = [0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4];
|
|
101
|
+
return { points, weights, knots };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=NURBSCurve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NURBSCurve.js","sourceRoot":"","sources":["../../src/core/NURBSCurve.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { BaseCurve } from './core/BaseCurve.js';
|
|
2
|
+
export { BezierCurve, buildAutoHandles, buildAlignedHandles, buildVectorHandles, buildFreeHandles } from './core/BezierCurve.js';
|
|
3
|
+
export { NURBSCurve, buildOpenUniformKnots, buildNURBSCircle } from './core/NURBSCurve.js';
|
|
4
|
+
export { CatmullRomCurve } from './core/CatmullRomCurve.js';
|
|
5
|
+
export { CurveTube, type CurveTubeOptions } from './operations/CurveTube.js';
|
|
6
|
+
export { CurveBevel, type CurveBevelOptions } from './operations/CurveBevel.js';
|
|
7
|
+
export { CurveLine, type CurveLineOptions } from './operations/CurveLine.js';
|
|
8
|
+
export { PathFollow } from './operations/PathFollow.js';
|
|
9
|
+
export { computeRMFrames, frameToMatrix, frameToQuaternion, type CurveFrame } from './utils/frames.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAChI,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAG3D,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5E,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC/E,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAGvD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Curve types
|
|
2
|
+
export { BaseCurve } from './core/BaseCurve.js';
|
|
3
|
+
export { BezierCurve, buildAutoHandles, buildAlignedHandles, buildVectorHandles, buildFreeHandles } from './core/BezierCurve.js';
|
|
4
|
+
export { NURBSCurve, buildOpenUniformKnots, buildNURBSCircle } from './core/NURBSCurve.js';
|
|
5
|
+
export { CatmullRomCurve } from './core/CatmullRomCurve.js';
|
|
6
|
+
// Operations
|
|
7
|
+
export { CurveTube } from './operations/CurveTube.js';
|
|
8
|
+
export { CurveBevel } from './operations/CurveBevel.js';
|
|
9
|
+
export { CurveLine } from './operations/CurveLine.js';
|
|
10
|
+
export { PathFollow } from './operations/PathFollow.js';
|
|
11
|
+
// Utils
|
|
12
|
+
export { computeRMFrames, frameToMatrix, frameToQuaternion } from './utils/frames.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAChI,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE3D,aAAa;AACb,OAAO,EAAE,SAAS,EAAyB,MAAM,2BAA2B,CAAA;AAC5E,OAAO,EAAE,UAAU,EAA0B,MAAM,4BAA4B,CAAA;AAC/E,OAAO,EAAE,SAAS,EAAyB,MAAM,2BAA2B,CAAA;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAEvD,QAAQ;AACR,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAmB,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BufferGeometry, Vector2 } from 'three';
|
|
2
|
+
import type { BaseCurve } from '../core/BaseCurve.js';
|
|
3
|
+
export interface CurveBevelOptions {
|
|
4
|
+
/** Number of cross-section rings. Blender: Resolution U. Default 64. */
|
|
5
|
+
tubularSegments?: number;
|
|
6
|
+
/** Scale applied to the profile. Default 1. */
|
|
7
|
+
profileScale?: number;
|
|
8
|
+
/** Blender: Bevel Factor Start — trim geometry to start at this fraction (0–1). Default 0. */
|
|
9
|
+
bevelFactorStart?: number;
|
|
10
|
+
/** Blender: Bevel Factor End — trim geometry to end at this fraction (0–1). Default 1. */
|
|
11
|
+
bevelFactorEnd?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* CurveBevel — extrude an arbitrary 2D profile along a 3D curve.
|
|
15
|
+
* Blender: curve object with Geometry > Bevel Object (a 2D curve profile).
|
|
16
|
+
*
|
|
17
|
+
* The profile is a list of 2D points (local XY) that gets stamped along each
|
|
18
|
+
* cross-section ring using the curve's rotation-minimizing frame.
|
|
19
|
+
*
|
|
20
|
+
* Built-in profiles: square, star, diamond, letter "C" shape.
|
|
21
|
+
* Or supply any list of Vector2 points for a custom profile.
|
|
22
|
+
*/
|
|
23
|
+
export declare class CurveBevel {
|
|
24
|
+
parameters: {
|
|
25
|
+
tubularSegments: number;
|
|
26
|
+
profileScale: number;
|
|
27
|
+
bevelFactorStart: number;
|
|
28
|
+
bevelFactorEnd: number;
|
|
29
|
+
};
|
|
30
|
+
/** 2D profile points (closed polygon). */
|
|
31
|
+
profile: Vector2[];
|
|
32
|
+
constructor(profile: Vector2[], opts?: CurveBevelOptions);
|
|
33
|
+
apply(curve: BaseCurve): BufferGeometry;
|
|
34
|
+
/** Circular profile — same result as CurveTube. */
|
|
35
|
+
static circle(radius?: number, sides?: number): Vector2[];
|
|
36
|
+
/** Square profile. */
|
|
37
|
+
static square(size?: number): Vector2[];
|
|
38
|
+
/** Diamond (rotated square). */
|
|
39
|
+
static diamond(size?: number): Vector2[];
|
|
40
|
+
/** Star profile. */
|
|
41
|
+
static star(outerR?: number, innerR?: number, points?: number): Vector2[];
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=CurveBevel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurveBevel.d.ts","sourceRoot":"","sources":["../../src/operations/CurveBevel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,OAAO,EAAW,MAAM,OAAO,CAAA;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGrD,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,0FAA0F;IAC1F,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACrB,UAAU,EAAE;QACV,eAAe,EAAE,MAAM,CAAA;QACvB,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,cAAc,EAAE,MAAM,CAAA;KACvB,CAAA;IAED,0CAA0C;IAC1C,OAAO,EAAE,OAAO,EAAE,CAAA;gBAEN,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,GAAE,iBAAsB;IAU5D,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc;IAqEvC,mDAAmD;IACnD,MAAM,CAAC,MAAM,CAAC,MAAM,SAAM,EAAE,KAAK,SAAK,GAAG,OAAO,EAAE;IAOlD,sBAAsB;IACtB,MAAM,CAAC,MAAM,CAAC,IAAI,SAAM,GAAG,OAAO,EAAE;IAKpC,gCAAgC;IAChC,MAAM,CAAC,OAAO,CAAC,IAAI,SAAM,GAAG,OAAO,EAAE;IAKrC,oBAAoB;IACpB,MAAM,CAAC,IAAI,CAAC,MAAM,SAAO,EAAE,MAAM,SAAO,EAAE,MAAM,SAAI,GAAG,OAAO,EAAE;CASjE"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { BufferGeometry, BufferAttribute, Vector2, Vector3 } from 'three';
|
|
2
|
+
import { computeRMFrames } from '../utils/frames.js';
|
|
3
|
+
/**
|
|
4
|
+
* CurveBevel — extrude an arbitrary 2D profile along a 3D curve.
|
|
5
|
+
* Blender: curve object with Geometry > Bevel Object (a 2D curve profile).
|
|
6
|
+
*
|
|
7
|
+
* The profile is a list of 2D points (local XY) that gets stamped along each
|
|
8
|
+
* cross-section ring using the curve's rotation-minimizing frame.
|
|
9
|
+
*
|
|
10
|
+
* Built-in profiles: square, star, diamond, letter "C" shape.
|
|
11
|
+
* Or supply any list of Vector2 points for a custom profile.
|
|
12
|
+
*/
|
|
13
|
+
export class CurveBevel {
|
|
14
|
+
constructor(profile, opts = {}) {
|
|
15
|
+
this.profile = profile;
|
|
16
|
+
this.parameters = {
|
|
17
|
+
tubularSegments: opts.tubularSegments ?? 64,
|
|
18
|
+
profileScale: opts.profileScale ?? 1,
|
|
19
|
+
bevelFactorStart: opts.bevelFactorStart ?? 0,
|
|
20
|
+
bevelFactorEnd: opts.bevelFactorEnd ?? 1,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
apply(curve) {
|
|
24
|
+
const { tubularSegments, profileScale, bevelFactorStart, bevelFactorEnd } = this.parameters;
|
|
25
|
+
const tubeSegs = Math.max(3, tubularSegments);
|
|
26
|
+
const profilePts = this.profile;
|
|
27
|
+
const profileN = profilePts.length;
|
|
28
|
+
const frameCount = tubeSegs + 1;
|
|
29
|
+
// Clamp bevel factors
|
|
30
|
+
const tStart = Math.max(0, Math.min(1, bevelFactorStart));
|
|
31
|
+
const tEnd = Math.max(tStart, Math.min(1, bevelFactorEnd));
|
|
32
|
+
const frames = _sampleFramesInRange(curve, frameCount, tStart, tEnd);
|
|
33
|
+
const vertCount = frameCount * profileN;
|
|
34
|
+
const positions = new Float32Array(vertCount * 3);
|
|
35
|
+
const normals = new Float32Array(vertCount * 3);
|
|
36
|
+
const uvs = new Float32Array(vertCount * 2);
|
|
37
|
+
let vi = 0, ui = 0;
|
|
38
|
+
for (let i = 0; i < frameCount; i++) {
|
|
39
|
+
const frame = frames[i];
|
|
40
|
+
const uStep = i / tubeSegs;
|
|
41
|
+
for (let j = 0; j < profileN; j++) {
|
|
42
|
+
const px = profilePts[j].x * profileScale;
|
|
43
|
+
const py = profilePts[j].y * profileScale;
|
|
44
|
+
positions[vi] = frame.position.x + frame.normal.x * px + frame.binormal.x * py;
|
|
45
|
+
positions[vi + 1] = frame.position.y + frame.normal.y * px + frame.binormal.y * py;
|
|
46
|
+
positions[vi + 2] = frame.position.z + frame.normal.z * px + frame.binormal.z * py;
|
|
47
|
+
// Approximate normals from profile edge directions
|
|
48
|
+
const next = profilePts[(j + 1) % profileN];
|
|
49
|
+
const ex = next.x - profilePts[j].x, ey = next.y - profilePts[j].y;
|
|
50
|
+
const nPx = ey, nPy = -ex;
|
|
51
|
+
const nLen = Math.sqrt(nPx * nPx + nPy * nPy) || 1;
|
|
52
|
+
normals[vi] = (frame.normal.x * nPx + frame.binormal.x * nPy) / nLen;
|
|
53
|
+
normals[vi + 1] = (frame.normal.y * nPx + frame.binormal.y * nPy) / nLen;
|
|
54
|
+
normals[vi + 2] = (frame.normal.z * nPx + frame.binormal.z * nPy) / nLen;
|
|
55
|
+
uvs[ui] = uStep;
|
|
56
|
+
uvs[ui + 1] = j / (profileN - 1);
|
|
57
|
+
vi += 3;
|
|
58
|
+
ui += 2;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const faceCount = tubeSegs * profileN * 2;
|
|
62
|
+
const indices = new Uint32Array(faceCount * 3);
|
|
63
|
+
let ii = 0;
|
|
64
|
+
for (let i = 0; i < tubeSegs; i++) {
|
|
65
|
+
for (let j = 0; j < profileN; j++) {
|
|
66
|
+
const a = profileN * i + j;
|
|
67
|
+
const b = profileN * (i + 1) + j;
|
|
68
|
+
const c = profileN * (i + 1) + (j + 1) % profileN;
|
|
69
|
+
const d = profileN * i + (j + 1) % profileN;
|
|
70
|
+
indices[ii++] = a;
|
|
71
|
+
indices[ii++] = b;
|
|
72
|
+
indices[ii++] = d;
|
|
73
|
+
indices[ii++] = b;
|
|
74
|
+
indices[ii++] = c;
|
|
75
|
+
indices[ii++] = d;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const geo = new BufferGeometry();
|
|
79
|
+
geo.setAttribute('position', new BufferAttribute(positions, 3));
|
|
80
|
+
geo.setAttribute('normal', new BufferAttribute(normals, 3));
|
|
81
|
+
geo.setAttribute('uv', new BufferAttribute(uvs, 2));
|
|
82
|
+
geo.setIndex(new BufferAttribute(indices, 1));
|
|
83
|
+
return geo;
|
|
84
|
+
}
|
|
85
|
+
// ── Built-in profiles ──────────────────────────────────────────────────────
|
|
86
|
+
/** Circular profile — same result as CurveTube. */
|
|
87
|
+
static circle(radius = 0.1, sides = 12) {
|
|
88
|
+
return Array.from({ length: sides }, (_, i) => {
|
|
89
|
+
const a = (i / sides) * Math.PI * 2;
|
|
90
|
+
return new Vector2(Math.cos(a) * radius, Math.sin(a) * radius);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/** Square profile. */
|
|
94
|
+
static square(size = 0.1) {
|
|
95
|
+
const h = size / 2;
|
|
96
|
+
return [new Vector2(-h, -h), new Vector2(h, -h), new Vector2(h, h), new Vector2(-h, h)];
|
|
97
|
+
}
|
|
98
|
+
/** Diamond (rotated square). */
|
|
99
|
+
static diamond(size = 0.1) {
|
|
100
|
+
const h = size / 2;
|
|
101
|
+
return [new Vector2(0, -h), new Vector2(h, 0), new Vector2(0, h), new Vector2(-h, 0)];
|
|
102
|
+
}
|
|
103
|
+
/** Star profile. */
|
|
104
|
+
static star(outerR = 0.12, innerR = 0.05, points = 5) {
|
|
105
|
+
const pts = [];
|
|
106
|
+
for (let i = 0; i < points * 2; i++) {
|
|
107
|
+
const a = (i / (points * 2)) * Math.PI * 2 - Math.PI / 2;
|
|
108
|
+
const r = i % 2 === 0 ? outerR : innerR;
|
|
109
|
+
pts.push(new Vector2(Math.cos(a) * r, Math.sin(a) * r));
|
|
110
|
+
}
|
|
111
|
+
return pts;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// ── Shared internal helper (same logic as CurveTube) ─────────────────────────
|
|
115
|
+
function _sampleFramesInRange(curve, count, tStart, tEnd) {
|
|
116
|
+
if (tStart === 0 && tEnd === 1) {
|
|
117
|
+
return computeRMFrames(curve, count);
|
|
118
|
+
}
|
|
119
|
+
const preCount = Math.max(count, 64);
|
|
120
|
+
const allFrames = computeRMFrames(curve, preCount);
|
|
121
|
+
const out = [];
|
|
122
|
+
for (let i = 0; i < count; i++) {
|
|
123
|
+
const u = count === 1 ? tStart : tStart + (tEnd - tStart) * (i / (count - 1));
|
|
124
|
+
out.push(_interpolateFrame(u, allFrames, preCount));
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
function _interpolateFrame(u, frames, frameCount) {
|
|
129
|
+
const idx = Math.min(Math.floor(u * (frameCount - 1)), frameCount - 2);
|
|
130
|
+
const alpha = u * (frameCount - 1) - idx;
|
|
131
|
+
const f0 = frames[idx];
|
|
132
|
+
const f1 = frames[idx + 1];
|
|
133
|
+
const position = new Vector3().lerpVectors(f0.position, f1.position, alpha);
|
|
134
|
+
const tangent = new Vector3().lerpVectors(f0.tangent, f1.tangent, alpha).normalize();
|
|
135
|
+
const normal = new Vector3().lerpVectors(f0.normal, f1.normal, alpha).normalize();
|
|
136
|
+
const binormal = new Vector3().crossVectors(tangent, normal).normalize();
|
|
137
|
+
const correctedNormal = new Vector3().crossVectors(binormal, tangent).normalize();
|
|
138
|
+
return { position, tangent, normal: correctedNormal, binormal };
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=CurveBevel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurveBevel.js","sourceRoot":"","sources":["../../src/operations/CurveBevel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BufferGeometry } from 'three';
|
|
2
|
+
import type { BaseCurve } from '../core/BaseCurve.js';
|
|
3
|
+
export interface CurveLineOptions {
|
|
4
|
+
/** Number of sample points. Default 128. */
|
|
5
|
+
points?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* CurveLine — sample a curve into a line BufferGeometry.
|
|
9
|
+
* Use with THREE.Line / THREE.LineLoop for wireframe curve visualization.
|
|
10
|
+
* Arc-length uniform sampling (constant density along the path).
|
|
11
|
+
*/
|
|
12
|
+
export declare class CurveLine {
|
|
13
|
+
parameters: {
|
|
14
|
+
points: number;
|
|
15
|
+
};
|
|
16
|
+
constructor(opts?: CurveLineOptions);
|
|
17
|
+
apply(curve: BaseCurve): BufferGeometry;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=CurveLine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurveLine.d.ts","sourceRoot":"","sources":["../../src/operations/CurveLine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,OAAO,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,qBAAa,SAAS;IACpB,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElB,IAAI,GAAE,gBAAqB;IAIvC,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc;CAaxC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BufferGeometry, BufferAttribute } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* CurveLine — sample a curve into a line BufferGeometry.
|
|
4
|
+
* Use with THREE.Line / THREE.LineLoop for wireframe curve visualization.
|
|
5
|
+
* Arc-length uniform sampling (constant density along the path).
|
|
6
|
+
*/
|
|
7
|
+
export class CurveLine {
|
|
8
|
+
constructor(opts = {}) {
|
|
9
|
+
this.parameters = { points: opts.points ?? 128 };
|
|
10
|
+
}
|
|
11
|
+
apply(curve) {
|
|
12
|
+
const count = Math.max(2, this.parameters.points);
|
|
13
|
+
const pts = curve.getSpacedPoints(count);
|
|
14
|
+
const positions = new Float32Array(count * 3);
|
|
15
|
+
pts.forEach((p, i) => {
|
|
16
|
+
positions[i * 3] = p.x;
|
|
17
|
+
positions[i * 3 + 1] = p.y;
|
|
18
|
+
positions[i * 3 + 2] = p.z;
|
|
19
|
+
});
|
|
20
|
+
const geo = new BufferGeometry();
|
|
21
|
+
geo.setAttribute('position', new BufferAttribute(positions, 3));
|
|
22
|
+
return geo;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=CurveLine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurveLine.js","sourceRoot":"","sources":["../../src/operations/CurveLine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAQvD;;;;GAIG;AACH,MAAM,OAAO,SAAS;IAGpB,YAAY,OAAyB,EAAE;QACrC,IAAI,CAAC,UAAU,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE,CAAA;IAClD,CAAC;IAED,KAAK,CAAC,KAAgB;QACpB,MAAM,KAAK,GAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QAClD,MAAM,GAAG,GAAM,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;QAC3C,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;QAC7C,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnB,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,GAAO,CAAC,CAAC,CAAC,CAAA;YAC1B,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;YAC1B,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAC5B,CAAC,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,IAAI,cAAc,EAAE,CAAA;QAChC,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAA;QAC/D,OAAO,GAAG,CAAA;IACZ,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BufferGeometry } from 'three';
|
|
2
|
+
import type { BaseCurve } from '../core/BaseCurve.js';
|
|
3
|
+
export interface CurveTubeOptions {
|
|
4
|
+
/** Number of cross-section rings along the tube. Blender: Resolution U. Default 64. */
|
|
5
|
+
tubularSegments?: number;
|
|
6
|
+
/** Number of sides per ring. Blender: Resolution V. Default 12. */
|
|
7
|
+
radialSegments?: number;
|
|
8
|
+
/** Tube radius. Blender: Bevel Depth. Default 0.1. */
|
|
9
|
+
radius?: number;
|
|
10
|
+
/** Close the tube at both ends (caps). Default false. */
|
|
11
|
+
closed?: boolean;
|
|
12
|
+
/** Blender: Bevel Factor Start — trim geometry to start at this fraction (0–1). Default 0. */
|
|
13
|
+
bevelFactorStart?: number;
|
|
14
|
+
/** Blender: Bevel Factor End — trim geometry to end at this fraction (0–1). Default 1. */
|
|
15
|
+
bevelFactorEnd?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* CurveTube — extrude a circle cross-section along a curve.
|
|
19
|
+
* Blender: curve object with Geometry > Bevel > Round mode.
|
|
20
|
+
*
|
|
21
|
+
* Returns a BufferGeometry with position, normal, and uv attributes.
|
|
22
|
+
* Non-destructive — always returns a new geometry.
|
|
23
|
+
*/
|
|
24
|
+
export declare class CurveTube {
|
|
25
|
+
parameters: {
|
|
26
|
+
tubularSegments: number;
|
|
27
|
+
radialSegments: number;
|
|
28
|
+
radius: number;
|
|
29
|
+
bevelFactorStart: number;
|
|
30
|
+
bevelFactorEnd: number;
|
|
31
|
+
};
|
|
32
|
+
closed: boolean;
|
|
33
|
+
constructor(opts?: CurveTubeOptions);
|
|
34
|
+
apply(curve: BaseCurve): BufferGeometry;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=CurveTube.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurveTube.d.ts","sourceRoot":"","sources":["../../src/operations/CurveTube.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA4B,MAAM,OAAO,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGrD,MAAM,WAAW,gBAAgB;IAC/B,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yDAAyD;IACzD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,0FAA0F;IAC1F,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,SAAS;IACpB,UAAU,EAAE;QACV,eAAe,EAAE,MAAM,CAAA;QACvB,cAAc,EAAE,MAAM,CAAA;QACtB,MAAM,EAAE,MAAM,CAAA;QACd,gBAAgB,EAAE,MAAM,CAAA;QACxB,cAAc,EAAE,MAAM,CAAA;KACvB,CAAA;IAED,MAAM,EAAE,OAAO,CAAA;gBAEH,IAAI,GAAE,gBAAqB;IAWvC,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc;CAqExC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { BufferGeometry, BufferAttribute, Vector3 } from 'three';
|
|
2
|
+
import { computeRMFrames } from '../utils/frames.js';
|
|
3
|
+
/**
|
|
4
|
+
* CurveTube — extrude a circle cross-section along a curve.
|
|
5
|
+
* Blender: curve object with Geometry > Bevel > Round mode.
|
|
6
|
+
*
|
|
7
|
+
* Returns a BufferGeometry with position, normal, and uv attributes.
|
|
8
|
+
* Non-destructive — always returns a new geometry.
|
|
9
|
+
*/
|
|
10
|
+
export class CurveTube {
|
|
11
|
+
constructor(opts = {}) {
|
|
12
|
+
this.parameters = {
|
|
13
|
+
tubularSegments: opts.tubularSegments ?? 64,
|
|
14
|
+
radialSegments: opts.radialSegments ?? 12,
|
|
15
|
+
radius: opts.radius ?? 0.1,
|
|
16
|
+
bevelFactorStart: opts.bevelFactorStart ?? 0,
|
|
17
|
+
bevelFactorEnd: opts.bevelFactorEnd ?? 1,
|
|
18
|
+
};
|
|
19
|
+
this.closed = opts.closed ?? false;
|
|
20
|
+
}
|
|
21
|
+
apply(curve) {
|
|
22
|
+
const { tubularSegments, radialSegments, radius, bevelFactorStart, bevelFactorEnd } = this.parameters;
|
|
23
|
+
const tubeSegs = Math.max(3, tubularSegments);
|
|
24
|
+
const radialSegs = Math.max(3, radialSegments);
|
|
25
|
+
const frameCount = tubeSegs + 1;
|
|
26
|
+
// Clamp bevel factors
|
|
27
|
+
const tStart = Math.max(0, Math.min(1, bevelFactorStart));
|
|
28
|
+
const tEnd = Math.max(tStart, Math.min(1, bevelFactorEnd));
|
|
29
|
+
// Sample full-curve frames and then remap u to [tStart, tEnd]
|
|
30
|
+
const frames = sampleFramesInRange(curve, frameCount, tStart, tEnd);
|
|
31
|
+
const vertCount = frameCount * (radialSegs + 1);
|
|
32
|
+
const positions = new Float32Array(vertCount * 3);
|
|
33
|
+
const normals = new Float32Array(vertCount * 3);
|
|
34
|
+
const uvs = new Float32Array(vertCount * 2);
|
|
35
|
+
let vi = 0, ui = 0;
|
|
36
|
+
for (let i = 0; i < frameCount; i++) {
|
|
37
|
+
const frame = frames[i];
|
|
38
|
+
const uStep = i / tubeSegs;
|
|
39
|
+
for (let j = 0; j <= radialSegs; j++) {
|
|
40
|
+
const angle = (j / radialSegs) * Math.PI * 2;
|
|
41
|
+
const cos = Math.cos(angle);
|
|
42
|
+
const sin = Math.sin(angle);
|
|
43
|
+
// Normal in the cross-section plane (normal * cos + binormal * sin)
|
|
44
|
+
const nx = frame.normal.x * cos + frame.binormal.x * sin;
|
|
45
|
+
const ny = frame.normal.y * cos + frame.binormal.y * sin;
|
|
46
|
+
const nz = frame.normal.z * cos + frame.binormal.z * sin;
|
|
47
|
+
positions[vi] = frame.position.x + nx * radius;
|
|
48
|
+
positions[vi + 1] = frame.position.y + ny * radius;
|
|
49
|
+
positions[vi + 2] = frame.position.z + nz * radius;
|
|
50
|
+
normals[vi] = nx;
|
|
51
|
+
normals[vi + 1] = ny;
|
|
52
|
+
normals[vi + 2] = nz;
|
|
53
|
+
uvs[ui] = uStep;
|
|
54
|
+
uvs[ui + 1] = j / radialSegs;
|
|
55
|
+
vi += 3;
|
|
56
|
+
ui += 2;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Indices
|
|
60
|
+
const indexCount = tubeSegs * radialSegs * 6;
|
|
61
|
+
const indices = new Uint32Array(indexCount);
|
|
62
|
+
let ii = 0;
|
|
63
|
+
for (let i = 0; i < tubeSegs; i++) {
|
|
64
|
+
for (let j = 0; j < radialSegs; j++) {
|
|
65
|
+
const a = (radialSegs + 1) * i + j;
|
|
66
|
+
const b = (radialSegs + 1) * (i + 1) + j;
|
|
67
|
+
const c = (radialSegs + 1) * (i + 1) + j + 1;
|
|
68
|
+
const d = (radialSegs + 1) * i + j + 1;
|
|
69
|
+
indices[ii++] = a;
|
|
70
|
+
indices[ii++] = b;
|
|
71
|
+
indices[ii++] = d;
|
|
72
|
+
indices[ii++] = b;
|
|
73
|
+
indices[ii++] = c;
|
|
74
|
+
indices[ii++] = d;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const geo = new BufferGeometry();
|
|
78
|
+
geo.setAttribute('position', new BufferAttribute(positions, 3));
|
|
79
|
+
geo.setAttribute('normal', new BufferAttribute(normals, 3));
|
|
80
|
+
geo.setAttribute('uv', new BufferAttribute(uvs, 2));
|
|
81
|
+
geo.setIndex(new BufferAttribute(indices, 1));
|
|
82
|
+
if (this.closed)
|
|
83
|
+
addCaps(geo, frames, radialSegs, radius);
|
|
84
|
+
return geo;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Sample RMF frames over the sub-range [tStart, tEnd] of the curve.
|
|
89
|
+
* When tStart=0 and tEnd=1 this is identical to computeRMFrames.
|
|
90
|
+
* When trimmed, frames are computed for the full curve first (for stable
|
|
91
|
+
* propagation), then the subset covering [tStart, tEnd] is returned.
|
|
92
|
+
*/
|
|
93
|
+
function sampleFramesInRange(curve, count, tStart, tEnd) {
|
|
94
|
+
if (tStart === 0 && tEnd === 1) {
|
|
95
|
+
return computeRMFrames(curve, count);
|
|
96
|
+
}
|
|
97
|
+
// We propagate RMF from 0 up to tEnd using a coarse pre-pass,
|
|
98
|
+
// then resample at `count` evenly-spaced positions within [tStart, tEnd].
|
|
99
|
+
// Strategy: compute enough frames for the whole [0, tEnd] range, then slice.
|
|
100
|
+
const lut = curve.buildArcLengthLUT(400);
|
|
101
|
+
// Build a temporary full-resolution frame set from 0..tEnd
|
|
102
|
+
const preCount = Math.max(count, 64);
|
|
103
|
+
const allFrames = computeRMFrames(curve, preCount);
|
|
104
|
+
// Map each output frame index to a t value in [tStart, tEnd]
|
|
105
|
+
const { computeRMFrameAt } = _rmfUtils(curve, lut);
|
|
106
|
+
const out = [];
|
|
107
|
+
for (let i = 0; i < count; i++) {
|
|
108
|
+
const u = count === 1 ? tStart : tStart + (tEnd - tStart) * (i / (count - 1));
|
|
109
|
+
out.push(computeRMFrameAt(u, allFrames, preCount));
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** Internal utility: interpolate a CurveFrame at curve parameter u by finding the closest frame. */
|
|
114
|
+
function _rmfUtils(curve, lut) {
|
|
115
|
+
function computeRMFrameAt(u, frames, frameCount) {
|
|
116
|
+
// Map u to the closest precomputed frame index
|
|
117
|
+
const idx = Math.min(Math.floor(u * (frameCount - 1)), frameCount - 2);
|
|
118
|
+
const alpha = u * (frameCount - 1) - idx;
|
|
119
|
+
const f0 = frames[idx];
|
|
120
|
+
const f1 = frames[idx + 1];
|
|
121
|
+
// Linearly interpolate position (good enough for sub-frame accuracy)
|
|
122
|
+
const position = new Vector3().lerpVectors(f0.position, f1.position, alpha);
|
|
123
|
+
const tangent = new Vector3().lerpVectors(f0.tangent, f1.tangent, alpha).normalize();
|
|
124
|
+
const normal = new Vector3().lerpVectors(f0.normal, f1.normal, alpha).normalize();
|
|
125
|
+
const binormal = new Vector3().crossVectors(tangent, normal).normalize();
|
|
126
|
+
// Re-orthogonalise normal against tangent
|
|
127
|
+
const correctedNormal = new Vector3().crossVectors(binormal, tangent).normalize();
|
|
128
|
+
return { position, tangent, normal: correctedNormal, binormal };
|
|
129
|
+
}
|
|
130
|
+
void lut;
|
|
131
|
+
return { computeRMFrameAt };
|
|
132
|
+
}
|
|
133
|
+
/** Add flat circular end caps. */
|
|
134
|
+
function addCaps(geo, frames, radialSegs, radius) {
|
|
135
|
+
// Caps can be added separately as CircleGeometry positioned at frame endpoints.
|
|
136
|
+
void geo;
|
|
137
|
+
void frames;
|
|
138
|
+
void radialSegs;
|
|
139
|
+
void radius;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=CurveTube.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CurveTube.js","sourceRoot":"","sources":["../../src/operations/CurveTube.ts"],"names":[],"mappings":"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"}
|