@math.gl/geometry 5.0.0-alpha.12 → 5.0.0-alpha.14

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.
@@ -0,0 +1,14 @@
1
+ import type { PrimitiveGeometryProps } from "../geometries/geometry-helpers.js";
2
+ import { ParametricGeometry } from "./parametric-geometry.js";
3
+ export type LatheGeometryProps = PrimitiveGeometryProps & {
4
+ /** Ordered [radius, height] profile, with nonnegative radii. */
5
+ points: readonly (readonly [number, number])[];
6
+ segments?: number;
7
+ phiStart?: number;
8
+ phiLength?: number;
9
+ };
10
+ /** Revolves a piecewise-linear profile around Y; smooth profile normals, no end caps. */
11
+ export declare class LatheGeometry extends ParametricGeometry {
12
+ constructor(props: LatheGeometryProps);
13
+ }
14
+ //# sourceMappingURL=lathe-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lathe-geometry.d.ts","sourceRoot":"","sources":["../../src/parametric/lathe-geometry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,sBAAsB,EAAC,0CAAuC;AAC3E,OAAO,EAAC,kBAAkB,EAAa,iCAA8B;AACrE,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,gEAAgE;IAChE,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AACF,yFAAyF;AACzF,qBAAa,aAAc,SAAQ,kBAAkB;gBACvC,KAAK,EAAE,kBAAkB;CAuDtC"}
@@ -0,0 +1,48 @@
1
+ import { ParametricGeometry, normalized } from "./parametric-geometry.js";
2
+ /** Revolves a piecewise-linear profile around Y; smooth profile normals, no end caps. */
3
+ export class LatheGeometry extends ParametricGeometry {
4
+ constructor(props) {
5
+ const { points, segments = 48, phiStart = 0, phiLength = Math.PI * 2 } = props;
6
+ if (!points ||
7
+ points.length < 2 ||
8
+ points.some(p => p.length !== 2 || !p.every(Number.isFinite) || p[0] < 0))
9
+ throw new RangeError('Lathe needs at least two finite [nonnegative radius, height] points');
10
+ if (!Number.isFinite(phiStart) ||
11
+ !Number.isFinite(phiLength) ||
12
+ phiLength <= 0 ||
13
+ phiLength > Math.PI * 2)
14
+ throw new RangeError('Invalid lathe angular sweep');
15
+ if (segments < 3)
16
+ throw new RangeError('Lathe requires at least three angular segments');
17
+ const profile = points.map(p => [...p]);
18
+ const edgeNormals = profile.slice(1).map((p, i) => {
19
+ const dr = p[0] - profile[i][0], dy = p[1] - profile[i][1];
20
+ if (dr === 0 && dy === 0)
21
+ throw new RangeError('Consecutive profile points must differ');
22
+ return normalized([dy, -dr, 0]);
23
+ });
24
+ const profileNormals = profile.map((_, i) => {
25
+ const before = edgeNormals[Math.max(0, i - 1)], after = edgeNormals[Math.min(i, edgeNormals.length - 1)];
26
+ return normalized(before.map((value, axis) => value + after[axis]));
27
+ });
28
+ const section = (v) => {
29
+ const coordinate = v * (profile.length - 1), i = Math.min(profile.length - 2, Math.floor(coordinate));
30
+ return { i, t: coordinate - i };
31
+ };
32
+ super({
33
+ ...props,
34
+ uSegments: segments,
35
+ vSegments: profile.length - 1,
36
+ periodicU: phiLength === Math.PI * 2,
37
+ sample: (u, v) => {
38
+ const { i, t } = section(v), radius = profile[i][0] * (1 - t) + profile[i + 1][0] * t, height = profile[i][1] * (1 - t) + profile[i + 1][1] * t, theta = phiStart + u * phiLength;
39
+ return [radius * Math.cos(theta), height, -radius * Math.sin(theta)];
40
+ },
41
+ normal: (u, v) => {
42
+ const { i, t } = section(v), n = profileNormals[i].map((value, axis) => value * (1 - t) + profileNormals[i + 1][axis] * t), theta = phiStart + u * phiLength;
43
+ return [n[0] * Math.cos(theta), n[1], -n[0] * Math.sin(theta)];
44
+ }
45
+ });
46
+ }
47
+ }
48
+ //# sourceMappingURL=lathe-geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lathe-geometry.js","sourceRoot":"","sources":["../../src/parametric/lathe-geometry.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,kBAAkB,EAAE,UAAU,EAAC,iCAA8B;AAQrE,yFAAyF;AACzF,MAAM,OAAO,aAAc,SAAQ,kBAAkB;IACnD,YAAY,KAAyB;QACnC,MAAM,EAAC,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,QAAQ,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,EAAC,GAAG,KAAK,CAAC;QAC7E,IACE,CAAC,MAAM;YACP,MAAM,CAAC,MAAM,GAAG,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAEzE,MAAM,IAAI,UAAU,CAAC,qEAAqE,CAAC,CAAC;QAC9F,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC1B,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YAC3B,SAAS,IAAI,CAAC;YACd,SAAS,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;YAEvB,MAAM,IAAI,UAAU,CAAC,6BAA6B,CAAC,CAAC;QACtD,IAAI,QAAQ,GAAG,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,gDAAgD,CAAC,CAAC;QACzF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAChD,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAC7B,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;gBAAE,MAAM,IAAI,UAAU,CAAC,wCAAwC,CAAC,CAAC;YACzF,OAAO,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QACH,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC1C,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAC5C,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3D,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE;YAC5B,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EACzC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YAC3D,OAAO,EAAC,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,CAAC,EAAC,CAAC;QAChC,CAAC,CAAC;QACF,KAAK,CAAC;YACJ,GAAG,KAAK;YACR,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC;YAC7B,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC,EAAE,GAAG,CAAC;YACpC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACf,MAAM,EAAC,CAAC,EAAE,CAAC,EAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACvB,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EACxD,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EACxD,KAAK,GAAG,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAC;gBACnC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACvE,CAAC;YACD,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACf,MAAM,EAAC,CAAC,EAAE,CAAC,EAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACvB,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CACvB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CACnE,EACD,KAAK,GAAG,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAC;gBACnC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACjE,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import { Geometry } from "../lib/geometry.js";
2
+ import { type PrimitiveGeometryProps } from "../geometries/geometry-helpers.js";
3
+ export type SurfaceSampler = (u: number, v: number) => Readonly<ArrayLike<number>>;
4
+ export type ParametricGeometryProps = PrimitiveGeometryProps & {
5
+ /** Samples the normalized [0,1]² parameter domain. */
6
+ sample: SurfaceSampler;
7
+ /** Optional analytic normals; otherwise estimated from neighboring samples. */
8
+ normal?: SurfaceSampler;
9
+ uSegments?: number;
10
+ vSegments?: number;
11
+ /** Closed axes duplicate their first position/normal at UV 1. */
12
+ periodicU?: boolean;
13
+ periodicV?: boolean;
14
+ };
15
+ /** Indexed surface grid. Front faces and normals follow ∂P/∂u × ∂P/∂v. */
16
+ export declare class ParametricGeometry extends Geometry {
17
+ constructor(props: ParametricGeometryProps);
18
+ }
19
+ export declare function normalized(vector: number[]): number[];
20
+ //# sourceMappingURL=parametric-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parametric-geometry.d.ts","sourceRoot":"","sources":["../../src/parametric/parametric-geometry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,QAAQ,EAAC,2BAAwB;AACzC,OAAO,EAAiB,KAAK,sBAAsB,EAAC,0CAAuC;AAE3F,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACnF,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,GAAG;IAC7D,sDAAsD;IACtD,MAAM,EAAE,cAAc,CAAC;IACvB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,0EAA0E;AAC1E,qBAAa,kBAAmB,SAAQ,QAAQ;gBAClC,KAAK,EAAE,uBAAuB;CAoF3C;AAMD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAMrD"}
@@ -0,0 +1,88 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ import { Geometry } from "../lib/geometry.js";
5
+ import { assertSegments } from "../geometries/geometry-helpers.js";
6
+ /** Indexed surface grid. Front faces and normals follow ∂P/∂u × ∂P/∂v. */
7
+ export class ParametricGeometry extends Geometry {
8
+ constructor(props) {
9
+ const { sample, normal, uSegments = 32, vSegments = 32, periodicU = false, periodicV = false } = props;
10
+ assertSegments(uSegments, 'uSegments');
11
+ assertSegments(vSegments, 'vSegments');
12
+ const count = (uSegments + 1) * (vSegments + 1);
13
+ const indexCount = uSegments * vSegments * 6;
14
+ if (!Number.isSafeInteger(indexCount) || indexCount > 0xffffffff)
15
+ throw new RangeError('Surface exceeds 32-bit index-buffer length');
16
+ if (!Number.isSafeInteger(count) || count > 0xffffffff)
17
+ throw new RangeError('Surface exceeds 32-bit indexing');
18
+ const positions = new Float32Array(count * 3), normals = new Float32Array(count * 3), uvs = new Float32Array(count * 2);
19
+ const canonical = (value, periodic) => periodic ? ((value % 1) + 1) % 1 : Math.max(0, Math.min(1, value));
20
+ const evaluate = (u, v) => readVector(sample(canonical(u, periodicU), canonical(v, periodicV)));
21
+ // A small finite-difference step estimates smooth-surface normals independently
22
+ // of tessellation density. Open boundaries use one-sided differences.
23
+ const step = 1e-5;
24
+ let row = 0;
25
+ for (let j = 0; j <= vSegments; j++)
26
+ for (let i = 0; i <= uSegments; i++, row++) {
27
+ const u = i / uSegments, v = j / vSegments;
28
+ const sampleU = canonical(u, periodicU), sampleV = canonical(v, periodicV);
29
+ positions.set(evaluate(sampleU, sampleV), row * 3);
30
+ let n;
31
+ if (normal)
32
+ n = readVector(normal(sampleU, sampleV));
33
+ else {
34
+ const left = evaluate(sampleU - step, sampleV), right = evaluate(sampleU + step, sampleV);
35
+ const below = evaluate(sampleU, sampleV - step), above = evaluate(sampleU, sampleV + step);
36
+ const du = normalized(right.map((value, axis) => value - left[axis]));
37
+ const dv = normalized(above.map((value, axis) => value - below[axis]));
38
+ n = [
39
+ du[1] * dv[2] - du[2] * dv[1],
40
+ du[2] * dv[0] - du[0] * dv[2],
41
+ du[0] * dv[1] - du[1] * dv[0]
42
+ ];
43
+ }
44
+ normals.set(normalized(n), row * 3);
45
+ uvs.set([u, v], row * 2);
46
+ }
47
+ for (const value of positions)
48
+ if (!Number.isFinite(value))
49
+ throw new RangeError('Positions must be representable as Float32');
50
+ const indices = count > 0xffff ? new Uint32Array(indexCount) : new Uint16Array(indexCount);
51
+ const stride = uSegments + 1;
52
+ let cursor = 0;
53
+ for (let j = 0; j < vSegments; j++)
54
+ for (let i = 0; i < uSegments; i++) {
55
+ const a = j * stride + i, b = a + 1, c = a + stride, d = c + 1;
56
+ indices[cursor++] = a;
57
+ indices[cursor++] = b;
58
+ indices[cursor++] = d;
59
+ indices[cursor++] = a;
60
+ indices[cursor++] = d;
61
+ indices[cursor++] = c;
62
+ }
63
+ super({
64
+ id: props.id,
65
+ topology: 'triangle-list',
66
+ indices,
67
+ attributes: {
68
+ POSITION: { size: 3, value: positions },
69
+ NORMAL: { size: 3, value: normals },
70
+ TEXCOORD_0: { size: 2, value: uvs },
71
+ ...props.attributes
72
+ }
73
+ });
74
+ }
75
+ }
76
+ function readVector(value) {
77
+ if (!value || value.length !== 3 || !Array.from(value).every(Number.isFinite))
78
+ throw new RangeError('Surface samples and normals must be finite triples');
79
+ return Array.from(value);
80
+ }
81
+ export function normalized(vector) {
82
+ const scale = Math.max(...vector.map(Math.abs));
83
+ if (!scale)
84
+ return [0, 0, 0];
85
+ const scaled = vector.map(value => value / scale), length = Math.hypot(...scaled);
86
+ return scaled.map(value => (value === 0 ? 0 : value / length));
87
+ }
88
+ //# sourceMappingURL=parametric-geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parametric-geometry.js","sourceRoot":"","sources":["../../src/parametric/parametric-geometry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type PrimitiveGeometryProps } from "../geometries/geometry-helpers.js";
2
+ import { ParametricGeometry } from "./parametric-geometry.js";
3
+ export type TorusGeometryProps = PrimitiveGeometryProps & {
4
+ majorRadius?: number;
5
+ minorRadius?: number;
6
+ majorSegments?: number;
7
+ minorSegments?: number;
8
+ /** Sweep in radians, (0, 2π]. Partial sweeps have open ends. */
9
+ arc?: number;
10
+ };
11
+ /** Ring torus around Y, with outward analytic normals and separate UV seam rows. */
12
+ export declare class TorusGeometry extends ParametricGeometry {
13
+ constructor(props?: TorusGeometryProps);
14
+ }
15
+ //# sourceMappingURL=torus-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"torus-geometry.d.ts","sourceRoot":"","sources":["../../src/parametric/torus-geometry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,sBAAsB,EAAC,0CAAuC;AAC3F,OAAO,EAAC,kBAAkB,EAAC,iCAA8B;AACzD,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AACF,oFAAoF;AACpF,qBAAa,aAAc,SAAQ,kBAAkB;gBACvC,KAAK,GAAE,kBAAuB;CAmC3C"}
@@ -0,0 +1,36 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ import { assertPositive } from "../geometries/geometry-helpers.js";
5
+ import { ParametricGeometry } from "./parametric-geometry.js";
6
+ /** Ring torus around Y, with outward analytic normals and separate UV seam rows. */
7
+ export class TorusGeometry extends ParametricGeometry {
8
+ constructor(props = {}) {
9
+ const { majorRadius = 1, minorRadius = 0.3, majorSegments = 48, minorSegments = 24, arc = Math.PI * 2 } = props;
10
+ assertPositive(majorRadius, 'majorRadius');
11
+ assertPositive(minorRadius, 'minorRadius');
12
+ if (minorRadius >= majorRadius)
13
+ throw new RangeError('Ring torus requires minorRadius < majorRadius');
14
+ if (!Number.isFinite(arc) || arc <= 0 || arc > Math.PI * 2)
15
+ throw new RangeError('arc must be in (0, 2π]');
16
+ if (majorSegments < 3 || minorSegments < 3)
17
+ throw new RangeError('Torus requires at least three segments per axis');
18
+ super({
19
+ ...props,
20
+ uSegments: majorSegments,
21
+ vSegments: minorSegments,
22
+ periodicU: arc === Math.PI * 2,
23
+ periodicV: true,
24
+ sample: (u, v) => {
25
+ const theta = u * arc, phi = v * Math.PI * 2, radius = majorRadius + minorRadius * Math.cos(phi);
26
+ return [radius * Math.cos(theta), minorRadius * Math.sin(phi), -radius * Math.sin(theta)];
27
+ },
28
+ normal: (u, v) => [
29
+ Math.cos(v * Math.PI * 2) * Math.cos(u * arc),
30
+ Math.sin(v * Math.PI * 2),
31
+ -Math.cos(v * Math.PI * 2) * Math.sin(u * arc)
32
+ ]
33
+ });
34
+ }
35
+ }
36
+ //# sourceMappingURL=torus-geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"torus-geometry.js","sourceRoot":"","sources":["../../src/parametric/torus-geometry.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,4DAA4D;AAC5D,OAAO,EAAC,cAAc,EAA8B,0CAAuC;AAC3F,OAAO,EAAC,kBAAkB,EAAC,iCAA8B;AASzD,oFAAoF;AACpF,MAAM,OAAO,aAAc,SAAQ,kBAAkB;IACnD,YAAY,QAA4B,EAAE;QACxC,MAAM,EACJ,WAAW,GAAG,CAAC,EACf,WAAW,GAAG,GAAG,EACjB,aAAa,GAAG,EAAE,EAClB,aAAa,GAAG,EAAE,EAClB,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,EAClB,GAAG,KAAK,CAAC;QACV,cAAc,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QAC3C,cAAc,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QAC3C,IAAI,WAAW,IAAI,WAAW;YAC5B,MAAM,IAAI,UAAU,CAAC,+CAA+C,CAAC,CAAC;QACxE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;YACxD,MAAM,IAAI,UAAU,CAAC,wBAAwB,CAAC,CAAC;QACjD,IAAI,aAAa,GAAG,CAAC,IAAI,aAAa,GAAG,CAAC;YACxC,MAAM,IAAI,UAAU,CAAC,iDAAiD,CAAC,CAAC;QAC1E,KAAK,CAAC;YACJ,GAAG,KAAK;YACR,SAAS,EAAE,aAAa;YACxB,SAAS,EAAE,aAAa;YACxB,SAAS,EAAE,GAAG,KAAK,IAAI,CAAC,EAAE,GAAG,CAAC;YAC9B,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACf,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,EACnB,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,EACrB,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACrD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5F,CAAC;YACD,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAChB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;gBAC7C,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;gBACzB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;aAC/C;SACF,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,276 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // dist/parametric.js
20
+ var parametric_exports = {};
21
+ __export(parametric_exports, {
22
+ LatheGeometry: () => LatheGeometry,
23
+ ParametricGeometry: () => ParametricGeometry,
24
+ TorusGeometry: () => TorusGeometry
25
+ });
26
+ module.exports = __toCommonJS(parametric_exports);
27
+
28
+ // dist/lib/geometry.js
29
+ var geometryId = 0;
30
+ var Geometry = class {
31
+ constructor(props) {
32
+ this.userData = {};
33
+ this.id = props.id || `geometry-${++geometryId}`;
34
+ this.topology = props.topology;
35
+ this.attributes = {};
36
+ let indices = props.indices ? normalizeAttribute(props.indices) : void 0;
37
+ for (const [name, input] of Object.entries(props.attributes || {})) {
38
+ const attribute = normalizeAttribute(input);
39
+ if (name === "POSITION" || name === "positions") {
40
+ attribute.size || (attribute.size = 3);
41
+ }
42
+ if (name === "indices") {
43
+ if (indices)
44
+ throw new Error("Geometry has multiple index attributes");
45
+ indices = attribute;
46
+ } else {
47
+ this.attributes[name] = attribute;
48
+ }
49
+ }
50
+ if (indices) {
51
+ if (!(indices.value instanceof Uint16Array || indices.value instanceof Uint32Array)) {
52
+ throw new Error("Geometry indices must be a Uint16Array or Uint32Array");
53
+ }
54
+ indices.size = 1;
55
+ this.indices = indices;
56
+ validateIndices(indices, this.attributes);
57
+ }
58
+ this.vertexCount = props.vertexCount ?? calculateVertexCount(this.attributes, this.indices);
59
+ if (!Number.isInteger(this.vertexCount) || this.vertexCount < 0) {
60
+ throw new Error("Geometry vertexCount must be a non-negative integer");
61
+ }
62
+ }
63
+ getVertexCount() {
64
+ return this.vertexCount;
65
+ }
66
+ getAttributes() {
67
+ return this.indices ? { indices: this.indices, ...this.attributes } : this.attributes;
68
+ }
69
+ };
70
+ function normalizeAttribute(input) {
71
+ const attribute = isTypedArray(input) ? { value: input } : { ...input };
72
+ if (!isTypedArray(attribute.value)) {
73
+ throw new Error("Geometry attributes must contain a typed-array value");
74
+ }
75
+ if (attribute.size !== void 0 && (!Number.isInteger(attribute.size) || attribute.size < 1)) {
76
+ throw new Error("Geometry attribute size must be a positive integer");
77
+ }
78
+ if (attribute.size && attribute.value.length % attribute.size !== 0) {
79
+ throw new Error("Geometry attribute length must be divisible by its size");
80
+ }
81
+ return attribute;
82
+ }
83
+ function isTypedArray(value) {
84
+ return ArrayBuffer.isView(value) && !(value instanceof DataView);
85
+ }
86
+ function validateIndices(indices, attributes) {
87
+ let maximumIndex = -1;
88
+ for (const index of indices.value)
89
+ maximumIndex = Math.max(maximumIndex, Number(index));
90
+ for (const [name, attribute] of Object.entries(attributes)) {
91
+ if (!attribute.constant && attribute.size) {
92
+ const attributeVertexCount = attribute.value.length / attribute.size;
93
+ if (maximumIndex >= attributeVertexCount) {
94
+ throw new Error(`Geometry index ${maximumIndex} exceeds ${name} vertex count ${attributeVertexCount}`);
95
+ }
96
+ }
97
+ }
98
+ }
99
+ function calculateVertexCount(attributes, indices) {
100
+ if (indices)
101
+ return indices.value.length;
102
+ let count = Infinity;
103
+ for (const attribute of Object.values(attributes)) {
104
+ if (!attribute.constant && attribute.size) {
105
+ count = Math.min(count, attribute.value.length / attribute.size);
106
+ }
107
+ }
108
+ if (!Number.isFinite(count))
109
+ throw new Error("Geometry has no countable attributes");
110
+ return count;
111
+ }
112
+
113
+ // dist/geometries/geometry-helpers.js
114
+ function assertPositive(value, name) {
115
+ if (!Number.isFinite(value) || value <= 0)
116
+ throw new Error(`${name} must be greater than zero`);
117
+ }
118
+ function assertSegments(value, name, minimum = 1) {
119
+ if (!Number.isInteger(value) || value < minimum)
120
+ throw new Error(`${name} must be an integer >= ${minimum}`);
121
+ }
122
+
123
+ // dist/parametric/parametric-geometry.js
124
+ var ParametricGeometry = class extends Geometry {
125
+ constructor(props) {
126
+ const { sample, normal, uSegments = 32, vSegments = 32, periodicU = false, periodicV = false } = props;
127
+ assertSegments(uSegments, "uSegments");
128
+ assertSegments(vSegments, "vSegments");
129
+ const count = (uSegments + 1) * (vSegments + 1);
130
+ const indexCount = uSegments * vSegments * 6;
131
+ if (!Number.isSafeInteger(indexCount) || indexCount > 4294967295)
132
+ throw new RangeError("Surface exceeds 32-bit index-buffer length");
133
+ if (!Number.isSafeInteger(count) || count > 4294967295)
134
+ throw new RangeError("Surface exceeds 32-bit indexing");
135
+ const positions = new Float32Array(count * 3), normals = new Float32Array(count * 3), uvs = new Float32Array(count * 2);
136
+ const canonical = (value, periodic) => periodic ? (value % 1 + 1) % 1 : Math.max(0, Math.min(1, value));
137
+ const evaluate = (u, v) => readVector(sample(canonical(u, periodicU), canonical(v, periodicV)));
138
+ const step = 1e-5;
139
+ let row = 0;
140
+ for (let j = 0; j <= vSegments; j++)
141
+ for (let i = 0; i <= uSegments; i++, row++) {
142
+ const u = i / uSegments, v = j / vSegments;
143
+ const sampleU = canonical(u, periodicU), sampleV = canonical(v, periodicV);
144
+ positions.set(evaluate(sampleU, sampleV), row * 3);
145
+ let n;
146
+ if (normal)
147
+ n = readVector(normal(sampleU, sampleV));
148
+ else {
149
+ const left = evaluate(sampleU - step, sampleV), right = evaluate(sampleU + step, sampleV);
150
+ const below = evaluate(sampleU, sampleV - step), above = evaluate(sampleU, sampleV + step);
151
+ const du = normalized(right.map((value, axis) => value - left[axis]));
152
+ const dv = normalized(above.map((value, axis) => value - below[axis]));
153
+ n = [
154
+ du[1] * dv[2] - du[2] * dv[1],
155
+ du[2] * dv[0] - du[0] * dv[2],
156
+ du[0] * dv[1] - du[1] * dv[0]
157
+ ];
158
+ }
159
+ normals.set(normalized(n), row * 3);
160
+ uvs.set([u, v], row * 2);
161
+ }
162
+ for (const value of positions)
163
+ if (!Number.isFinite(value))
164
+ throw new RangeError("Positions must be representable as Float32");
165
+ const indices = count > 65535 ? new Uint32Array(indexCount) : new Uint16Array(indexCount);
166
+ const stride = uSegments + 1;
167
+ let cursor = 0;
168
+ for (let j = 0; j < vSegments; j++)
169
+ for (let i = 0; i < uSegments; i++) {
170
+ const a = j * stride + i, b = a + 1, c = a + stride, d = c + 1;
171
+ indices[cursor++] = a;
172
+ indices[cursor++] = b;
173
+ indices[cursor++] = d;
174
+ indices[cursor++] = a;
175
+ indices[cursor++] = d;
176
+ indices[cursor++] = c;
177
+ }
178
+ super({
179
+ id: props.id,
180
+ topology: "triangle-list",
181
+ indices,
182
+ attributes: {
183
+ POSITION: { size: 3, value: positions },
184
+ NORMAL: { size: 3, value: normals },
185
+ TEXCOORD_0: { size: 2, value: uvs },
186
+ ...props.attributes
187
+ }
188
+ });
189
+ }
190
+ };
191
+ function readVector(value) {
192
+ if (!value || value.length !== 3 || !Array.from(value).every(Number.isFinite))
193
+ throw new RangeError("Surface samples and normals must be finite triples");
194
+ return Array.from(value);
195
+ }
196
+ function normalized(vector) {
197
+ const scale = Math.max(...vector.map(Math.abs));
198
+ if (!scale)
199
+ return [0, 0, 0];
200
+ const scaled = vector.map((value) => value / scale), length = Math.hypot(...scaled);
201
+ return scaled.map((value) => value === 0 ? 0 : value / length);
202
+ }
203
+
204
+ // dist/parametric/torus-geometry.js
205
+ var TorusGeometry = class extends ParametricGeometry {
206
+ constructor(props = {}) {
207
+ const { majorRadius = 1, minorRadius = 0.3, majorSegments = 48, minorSegments = 24, arc = Math.PI * 2 } = props;
208
+ assertPositive(majorRadius, "majorRadius");
209
+ assertPositive(minorRadius, "minorRadius");
210
+ if (minorRadius >= majorRadius)
211
+ throw new RangeError("Ring torus requires minorRadius < majorRadius");
212
+ if (!Number.isFinite(arc) || arc <= 0 || arc > Math.PI * 2)
213
+ throw new RangeError("arc must be in (0, 2\u03C0]");
214
+ if (majorSegments < 3 || minorSegments < 3)
215
+ throw new RangeError("Torus requires at least three segments per axis");
216
+ super({
217
+ ...props,
218
+ uSegments: majorSegments,
219
+ vSegments: minorSegments,
220
+ periodicU: arc === Math.PI * 2,
221
+ periodicV: true,
222
+ sample: (u, v) => {
223
+ const theta = u * arc, phi = v * Math.PI * 2, radius = majorRadius + minorRadius * Math.cos(phi);
224
+ return [radius * Math.cos(theta), minorRadius * Math.sin(phi), -radius * Math.sin(theta)];
225
+ },
226
+ normal: (u, v) => [
227
+ Math.cos(v * Math.PI * 2) * Math.cos(u * arc),
228
+ Math.sin(v * Math.PI * 2),
229
+ -Math.cos(v * Math.PI * 2) * Math.sin(u * arc)
230
+ ]
231
+ });
232
+ }
233
+ };
234
+
235
+ // dist/parametric/lathe-geometry.js
236
+ var LatheGeometry = class extends ParametricGeometry {
237
+ constructor(props) {
238
+ const { points, segments = 48, phiStart = 0, phiLength = Math.PI * 2 } = props;
239
+ if (!points || points.length < 2 || points.some((p) => p.length !== 2 || !p.every(Number.isFinite) || p[0] < 0))
240
+ throw new RangeError("Lathe needs at least two finite [nonnegative radius, height] points");
241
+ if (!Number.isFinite(phiStart) || !Number.isFinite(phiLength) || phiLength <= 0 || phiLength > Math.PI * 2)
242
+ throw new RangeError("Invalid lathe angular sweep");
243
+ if (segments < 3)
244
+ throw new RangeError("Lathe requires at least three angular segments");
245
+ const profile = points.map((p) => [...p]);
246
+ const edgeNormals = profile.slice(1).map((p, i) => {
247
+ const dr = p[0] - profile[i][0], dy = p[1] - profile[i][1];
248
+ if (dr === 0 && dy === 0)
249
+ throw new RangeError("Consecutive profile points must differ");
250
+ return normalized([dy, -dr, 0]);
251
+ });
252
+ const profileNormals = profile.map((_, i) => {
253
+ const before = edgeNormals[Math.max(0, i - 1)], after = edgeNormals[Math.min(i, edgeNormals.length - 1)];
254
+ return normalized(before.map((value, axis) => value + after[axis]));
255
+ });
256
+ const section = (v) => {
257
+ const coordinate = v * (profile.length - 1), i = Math.min(profile.length - 2, Math.floor(coordinate));
258
+ return { i, t: coordinate - i };
259
+ };
260
+ super({
261
+ ...props,
262
+ uSegments: segments,
263
+ vSegments: profile.length - 1,
264
+ periodicU: phiLength === Math.PI * 2,
265
+ sample: (u, v) => {
266
+ const { i, t } = section(v), radius = profile[i][0] * (1 - t) + profile[i + 1][0] * t, height = profile[i][1] * (1 - t) + profile[i + 1][1] * t, theta = phiStart + u * phiLength;
267
+ return [radius * Math.cos(theta), height, -radius * Math.sin(theta)];
268
+ },
269
+ normal: (u, v) => {
270
+ const { i, t } = section(v), n = profileNormals[i].map((value, axis) => value * (1 - t) + profileNormals[i + 1][axis] * t), theta = phiStart + u * phiLength;
271
+ return [n[0] * Math.cos(theta), n[1], -n[0] * Math.sin(theta)];
272
+ }
273
+ });
274
+ }
275
+ };
276
+ //# sourceMappingURL=parametric.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/parametric.ts", "../src/lib/geometry.ts", "../src/geometries/geometry-helpers.ts", "../src/parametric/parametric-geometry.ts", "../src/parametric/torus-geometry.ts", "../src/parametric/lathe-geometry.ts"],
4
+ "mappings": "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",
5
+ "names": []
6
+ }
@@ -0,0 +1,7 @@
1
+ export { ParametricGeometry } from "./parametric/parametric-geometry.js";
2
+ export type { ParametricGeometryProps, SurfaceSampler } from "./parametric/parametric-geometry.js";
3
+ export { TorusGeometry } from "./parametric/torus-geometry.js";
4
+ export type { TorusGeometryProps } from "./parametric/torus-geometry.js";
5
+ export { LatheGeometry } from "./parametric/lathe-geometry.js";
6
+ export type { LatheGeometryProps } from "./parametric/lathe-geometry.js";
7
+ //# sourceMappingURL=parametric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parametric.d.ts","sourceRoot":"","sources":["../src/parametric.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,kBAAkB,EAAC,4CAAyC;AACpE,YAAY,EAAC,uBAAuB,EAAE,cAAc,EAAC,4CAAyC;AAC9F,OAAO,EAAC,aAAa,EAAC,uCAAoC;AAC1D,YAAY,EAAC,kBAAkB,EAAC,uCAAoC;AACpE,OAAO,EAAC,aAAa,EAAC,uCAAoC;AAC1D,YAAY,EAAC,kBAAkB,EAAC,uCAAoC"}
@@ -0,0 +1,7 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ export { ParametricGeometry } from "./parametric/parametric-geometry.js";
5
+ export { TorusGeometry } from "./parametric/torus-geometry.js";
6
+ export { LatheGeometry } from "./parametric/lathe-geometry.js";
7
+ //# sourceMappingURL=parametric.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parametric.js","sourceRoot":"","sources":["../src/parametric.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,4DAA4D;AAC5D,OAAO,EAAC,kBAAkB,EAAC,4CAAyC;AAEpE,OAAO,EAAC,aAAa,EAAC,uCAAoC;AAE1D,OAAO,EAAC,aAAa,EAAC,uCAAoC"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
- "version": "5.0.0-alpha.12",
9
+ "version": "5.0.0-alpha.14",
10
10
  "keywords": [
11
11
  "geometry",
12
12
  "gltf",
@@ -27,6 +27,11 @@
27
27
  "types": "./dist/index.d.ts",
28
28
  "import": "./dist/index.js",
29
29
  "require": "./dist/index.cjs"
30
+ },
31
+ "./parametric": {
32
+ "types": "./dist/parametric.d.ts",
33
+ "import": "./dist/parametric.js",
34
+ "require": "./dist/parametric.cjs"
30
35
  }
31
36
  },
32
37
  "files": [
@@ -34,7 +39,7 @@
34
39
  "src"
35
40
  ],
36
41
  "dependencies": {
37
- "@math.gl/types": "5.0.0-alpha.12"
42
+ "@math.gl/types": "5.0.0-alpha.14"
38
43
  },
39
- "gitHead": "9f9ed72b110b898a5e2df55984b6cff67f8feab2"
44
+ "gitHead": "c4f1cbdd7fc9136a873efc511356cace8ff0001a"
40
45
  }
@@ -0,0 +1,70 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ import type {PrimitiveGeometryProps} from '../geometries/geometry-helpers';
5
+ import {ParametricGeometry, normalized} from './parametric-geometry';
6
+ export type LatheGeometryProps = PrimitiveGeometryProps & {
7
+ /** Ordered [radius, height] profile, with nonnegative radii. */
8
+ points: readonly (readonly [number, number])[];
9
+ segments?: number;
10
+ phiStart?: number;
11
+ phiLength?: number;
12
+ };
13
+ /** Revolves a piecewise-linear profile around Y; smooth profile normals, no end caps. */
14
+ export class LatheGeometry extends ParametricGeometry {
15
+ constructor(props: LatheGeometryProps) {
16
+ const {points, segments = 48, phiStart = 0, phiLength = Math.PI * 2} = props;
17
+ if (
18
+ !points ||
19
+ points.length < 2 ||
20
+ points.some(p => p.length !== 2 || !p.every(Number.isFinite) || p[0] < 0)
21
+ )
22
+ throw new RangeError('Lathe needs at least two finite [nonnegative radius, height] points');
23
+ if (
24
+ !Number.isFinite(phiStart) ||
25
+ !Number.isFinite(phiLength) ||
26
+ phiLength <= 0 ||
27
+ phiLength > Math.PI * 2
28
+ )
29
+ throw new RangeError('Invalid lathe angular sweep');
30
+ if (segments < 3) throw new RangeError('Lathe requires at least three angular segments');
31
+ const profile = points.map(p => [...p]);
32
+ const edgeNormals = profile.slice(1).map((p, i) => {
33
+ const dr = p[0] - profile[i][0],
34
+ dy = p[1] - profile[i][1];
35
+ if (dr === 0 && dy === 0) throw new RangeError('Consecutive profile points must differ');
36
+ return normalized([dy, -dr, 0]);
37
+ });
38
+ const profileNormals = profile.map((_, i) => {
39
+ const before = edgeNormals[Math.max(0, i - 1)],
40
+ after = edgeNormals[Math.min(i, edgeNormals.length - 1)];
41
+ return normalized(before.map((value, axis) => value + after[axis]));
42
+ });
43
+ const section = (v: number) => {
44
+ const coordinate = v * (profile.length - 1),
45
+ i = Math.min(profile.length - 2, Math.floor(coordinate));
46
+ return {i, t: coordinate - i};
47
+ };
48
+ super({
49
+ ...props,
50
+ uSegments: segments,
51
+ vSegments: profile.length - 1,
52
+ periodicU: phiLength === Math.PI * 2,
53
+ sample: (u, v) => {
54
+ const {i, t} = section(v),
55
+ radius = profile[i][0] * (1 - t) + profile[i + 1][0] * t,
56
+ height = profile[i][1] * (1 - t) + profile[i + 1][1] * t,
57
+ theta = phiStart + u * phiLength;
58
+ return [radius * Math.cos(theta), height, -radius * Math.sin(theta)];
59
+ },
60
+ normal: (u, v) => {
61
+ const {i, t} = section(v),
62
+ n = profileNormals[i].map(
63
+ (value, axis) => value * (1 - t) + profileNormals[i + 1][axis] * t
64
+ ),
65
+ theta = phiStart + u * phiLength;
66
+ return [n[0] * Math.cos(theta), n[1], -n[0] * Math.sin(theta)];
67
+ }
68
+ });
69
+ }
70
+ }
@@ -0,0 +1,118 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ import {Geometry} from '../lib/geometry';
5
+ import {assertSegments, type PrimitiveGeometryProps} from '../geometries/geometry-helpers';
6
+
7
+ export type SurfaceSampler = (u: number, v: number) => Readonly<ArrayLike<number>>;
8
+ export type ParametricGeometryProps = PrimitiveGeometryProps & {
9
+ /** Samples the normalized [0,1]² parameter domain. */
10
+ sample: SurfaceSampler;
11
+ /** Optional analytic normals; otherwise estimated from neighboring samples. */
12
+ normal?: SurfaceSampler;
13
+ uSegments?: number;
14
+ vSegments?: number;
15
+ /** Closed axes duplicate their first position/normal at UV 1. */
16
+ periodicU?: boolean;
17
+ periodicV?: boolean;
18
+ };
19
+
20
+ /** Indexed surface grid. Front faces and normals follow ∂P/∂u × ∂P/∂v. */
21
+ export class ParametricGeometry extends Geometry {
22
+ constructor(props: ParametricGeometryProps) {
23
+ const {
24
+ sample,
25
+ normal,
26
+ uSegments = 32,
27
+ vSegments = 32,
28
+ periodicU = false,
29
+ periodicV = false
30
+ } = props;
31
+ assertSegments(uSegments, 'uSegments');
32
+ assertSegments(vSegments, 'vSegments');
33
+ const count = (uSegments + 1) * (vSegments + 1);
34
+ const indexCount = uSegments * vSegments * 6;
35
+ if (!Number.isSafeInteger(indexCount) || indexCount > 0xffffffff)
36
+ throw new RangeError('Surface exceeds 32-bit index-buffer length');
37
+ if (!Number.isSafeInteger(count) || count > 0xffffffff)
38
+ throw new RangeError('Surface exceeds 32-bit indexing');
39
+ const positions = new Float32Array(count * 3),
40
+ normals = new Float32Array(count * 3),
41
+ uvs = new Float32Array(count * 2);
42
+ const canonical = (value: number, periodic: boolean) =>
43
+ periodic ? ((value % 1) + 1) % 1 : Math.max(0, Math.min(1, value));
44
+ const evaluate = (u: number, v: number) =>
45
+ readVector(sample(canonical(u, periodicU), canonical(v, periodicV)));
46
+ // A small finite-difference step estimates smooth-surface normals independently
47
+ // of tessellation density. Open boundaries use one-sided differences.
48
+ const step = 1e-5;
49
+ let row = 0;
50
+ for (let j = 0; j <= vSegments; j++)
51
+ for (let i = 0; i <= uSegments; i++, row++) {
52
+ const u = i / uSegments,
53
+ v = j / vSegments;
54
+ const sampleU = canonical(u, periodicU),
55
+ sampleV = canonical(v, periodicV);
56
+ positions.set(evaluate(sampleU, sampleV), row * 3);
57
+ let n: number[];
58
+ if (normal) n = readVector(normal(sampleU, sampleV));
59
+ else {
60
+ const left = evaluate(sampleU - step, sampleV),
61
+ right = evaluate(sampleU + step, sampleV);
62
+ const below = evaluate(sampleU, sampleV - step),
63
+ above = evaluate(sampleU, sampleV + step);
64
+ const du = normalized(right.map((value, axis) => value - left[axis]));
65
+ const dv = normalized(above.map((value, axis) => value - below[axis]));
66
+ n = [
67
+ du[1] * dv[2] - du[2] * dv[1],
68
+ du[2] * dv[0] - du[0] * dv[2],
69
+ du[0] * dv[1] - du[1] * dv[0]
70
+ ];
71
+ }
72
+ normals.set(normalized(n), row * 3);
73
+ uvs.set([u, v], row * 2);
74
+ }
75
+ for (const value of positions)
76
+ if (!Number.isFinite(value))
77
+ throw new RangeError('Positions must be representable as Float32');
78
+ const indices = count > 0xffff ? new Uint32Array(indexCount) : new Uint16Array(indexCount);
79
+ const stride = uSegments + 1;
80
+ let cursor = 0;
81
+ for (let j = 0; j < vSegments; j++)
82
+ for (let i = 0; i < uSegments; i++) {
83
+ const a = j * stride + i,
84
+ b = a + 1,
85
+ c = a + stride,
86
+ d = c + 1;
87
+ indices[cursor++] = a;
88
+ indices[cursor++] = b;
89
+ indices[cursor++] = d;
90
+ indices[cursor++] = a;
91
+ indices[cursor++] = d;
92
+ indices[cursor++] = c;
93
+ }
94
+ super({
95
+ id: props.id,
96
+ topology: 'triangle-list',
97
+ indices,
98
+ attributes: {
99
+ POSITION: {size: 3, value: positions},
100
+ NORMAL: {size: 3, value: normals},
101
+ TEXCOORD_0: {size: 2, value: uvs},
102
+ ...props.attributes
103
+ }
104
+ });
105
+ }
106
+ }
107
+ function readVector(value: Readonly<ArrayLike<number>>): number[] {
108
+ if (!value || value.length !== 3 || !Array.from(value).every(Number.isFinite))
109
+ throw new RangeError('Surface samples and normals must be finite triples');
110
+ return Array.from(value);
111
+ }
112
+ export function normalized(vector: number[]): number[] {
113
+ const scale = Math.max(...vector.map(Math.abs));
114
+ if (!scale) return [0, 0, 0];
115
+ const scaled = vector.map(value => value / scale),
116
+ length = Math.hypot(...scaled);
117
+ return scaled.map(value => (value === 0 ? 0 : value / length));
118
+ }
@@ -0,0 +1,51 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ import {assertPositive, type PrimitiveGeometryProps} from '../geometries/geometry-helpers';
5
+ import {ParametricGeometry} from './parametric-geometry';
6
+ export type TorusGeometryProps = PrimitiveGeometryProps & {
7
+ majorRadius?: number;
8
+ minorRadius?: number;
9
+ majorSegments?: number;
10
+ minorSegments?: number;
11
+ /** Sweep in radians, (0, 2π]. Partial sweeps have open ends. */
12
+ arc?: number;
13
+ };
14
+ /** Ring torus around Y, with outward analytic normals and separate UV seam rows. */
15
+ export class TorusGeometry extends ParametricGeometry {
16
+ constructor(props: TorusGeometryProps = {}) {
17
+ const {
18
+ majorRadius = 1,
19
+ minorRadius = 0.3,
20
+ majorSegments = 48,
21
+ minorSegments = 24,
22
+ arc = Math.PI * 2
23
+ } = props;
24
+ assertPositive(majorRadius, 'majorRadius');
25
+ assertPositive(minorRadius, 'minorRadius');
26
+ if (minorRadius >= majorRadius)
27
+ throw new RangeError('Ring torus requires minorRadius < majorRadius');
28
+ if (!Number.isFinite(arc) || arc <= 0 || arc > Math.PI * 2)
29
+ throw new RangeError('arc must be in (0, 2π]');
30
+ if (majorSegments < 3 || minorSegments < 3)
31
+ throw new RangeError('Torus requires at least three segments per axis');
32
+ super({
33
+ ...props,
34
+ uSegments: majorSegments,
35
+ vSegments: minorSegments,
36
+ periodicU: arc === Math.PI * 2,
37
+ periodicV: true,
38
+ sample: (u, v) => {
39
+ const theta = u * arc,
40
+ phi = v * Math.PI * 2,
41
+ radius = majorRadius + minorRadius * Math.cos(phi);
42
+ return [radius * Math.cos(theta), minorRadius * Math.sin(phi), -radius * Math.sin(theta)];
43
+ },
44
+ normal: (u, v) => [
45
+ Math.cos(v * Math.PI * 2) * Math.cos(u * arc),
46
+ Math.sin(v * Math.PI * 2),
47
+ -Math.cos(v * Math.PI * 2) * Math.sin(u * arc)
48
+ ]
49
+ });
50
+ }
51
+ }
@@ -0,0 +1,9 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ export {ParametricGeometry} from './parametric/parametric-geometry';
5
+ export type {ParametricGeometryProps, SurfaceSampler} from './parametric/parametric-geometry';
6
+ export {TorusGeometry} from './parametric/torus-geometry';
7
+ export type {TorusGeometryProps} from './parametric/torus-geometry';
8
+ export {LatheGeometry} from './parametric/lathe-geometry';
9
+ export type {LatheGeometryProps} from './parametric/lathe-geometry';