@danielsimonjr/sciengjs 0.7.0 → 0.8.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.
@@ -0,0 +1,195 @@
1
+ import { RenderError } from "../errors.js";
2
+ import { DEFAULT_SEGMENTS } from "./cad-document.js";
3
+ /** The one WASM module of this process. The module loads once, and every build shares the module. */
4
+ let manifoldPromise;
5
+ /** Loads the WASM module once. A failed load clears the cache so that a later build tries again. */
6
+ export function loadManifold() {
7
+ if (manifoldPromise === undefined) {
8
+ const started = import("manifold-3d").then(async (mod) => {
9
+ const wasm = (await mod.default());
10
+ wasm.setup();
11
+ return wasm;
12
+ });
13
+ manifoldPromise = started;
14
+ started.catch(() => {
15
+ if (manifoldPromise === started)
16
+ manifoldPromise = undefined;
17
+ });
18
+ }
19
+ return manifoldPromise;
20
+ }
21
+ /** The angle in degrees above which the build keeps an edge sharp in the normals. */
22
+ const SHARP_ANGLE = 60;
23
+ /** The normal channel of manifold-3d: channel 0 is the first property after x, y and z. */
24
+ const NORMAL_CHANNEL = 0;
25
+ /** The property index of the first normal component in the output mesh. */
26
+ const NORMAL_OFFSET = 3 + NORMAL_CHANNEL;
27
+ const vec3 = (v) => (typeof v === "number" ? [v, v, v] : v);
28
+ /** The build state: the module, the default segments, the colour of each original solid and every live object. */
29
+ class Build {
30
+ m;
31
+ segments;
32
+ maxFacets;
33
+ colors = new Map();
34
+ live = [];
35
+ constructor(m, segments, maxFacets) {
36
+ this.m = m;
37
+ this.segments = segments;
38
+ this.maxFacets = maxFacets;
39
+ }
40
+ /** Rejects with E_LIMIT when a solid has more facets than the limit. An operation can add facets. */
41
+ checkFacets(solid) {
42
+ const facets = solid.numTri();
43
+ if (facets > this.maxFacets) {
44
+ throw new RenderError("E_LIMIT", `the model has ${facets} facets; the limit is ${this.maxFacets}`);
45
+ }
46
+ return solid;
47
+ }
48
+ /** Keeps an object for the final clean-up and returns it. */
49
+ keep(value) {
50
+ this.live.push(value);
51
+ return value;
52
+ }
53
+ /** Frees every WASM object of the build. */
54
+ free() {
55
+ for (const value of this.live)
56
+ value.delete();
57
+ this.live.length = 0;
58
+ }
59
+ /** Marks a primitive as an original solid with a colour, so the faces of the result keep the colour. */
60
+ primitive(solid, color) {
61
+ const original = this.keep(solid.asOriginal());
62
+ this.colors.set(original.originalID(), color);
63
+ return original;
64
+ }
65
+ profile(node) {
66
+ const { CrossSection } = this.m;
67
+ switch (node.type) {
68
+ case "rectangle":
69
+ return this.keep(CrossSection.square(typeof node.size === "number" ? [node.size, node.size] : node.size, node.center ?? false));
70
+ case "circle":
71
+ return this.keep(CrossSection.circle(node.radius, node.segments ?? this.segments));
72
+ default:
73
+ return this.keep(CrossSection.ofPolygons([node.points]));
74
+ }
75
+ }
76
+ solid(node, inherited) {
77
+ const color = node.color ?? inherited;
78
+ const { Manifold } = this.m;
79
+ switch (node.type) {
80
+ case "cube":
81
+ return this.primitive(this.keep(Manifold.cube(vec3(node.size), node.center ?? false)), color);
82
+ case "cylinder": {
83
+ const low = node.radius ?? node.radius1;
84
+ const high = node.radius ?? node.radius2;
85
+ return this.primitive(this.keep(Manifold.cylinder(node.height, low, high, node.segments ?? this.segments, node.center ?? false)), color);
86
+ }
87
+ case "sphere":
88
+ return this.primitive(this.keep(Manifold.sphere(node.radius, node.segments ?? this.segments)), color);
89
+ case "polyhedron":
90
+ return this.primitive(this.polyhedron(node.points, node.faces), color);
91
+ case "extrude": {
92
+ const profileColor = node.child.color ?? color;
93
+ // manifold-3d 3.2.1 reads a number scaleTop as [n, 0]: always pass both components.
94
+ const scale = typeof node.scale === "number" ? [node.scale, node.scale] : (node.scale ?? [1, 1]);
95
+ const solid = this.profile(node.child).extrude(node.height, node.divisions ?? 0, node.twist ?? 0, scale, node.center ?? false);
96
+ return this.primitive(this.keep(solid), profileColor);
97
+ }
98
+ case "revolve": {
99
+ const solid = this.profile(node.child).revolve(node.segments ?? this.segments, node.degrees ?? 360);
100
+ return this.primitive(this.keep(solid), node.child.color ?? color);
101
+ }
102
+ case "union":
103
+ case "difference":
104
+ case "intersection": {
105
+ const parts = node.children.map((child) => this.solid(child, color));
106
+ if (parts.length === 1)
107
+ return parts[0];
108
+ return this.checkFacets(this.keep(Manifold[node.type](parts)));
109
+ }
110
+ case "translate":
111
+ return this.keep(this.solid(node.child, color).translate(node.offset));
112
+ case "rotate":
113
+ return this.keep(this.solid(node.child, color).rotate(node.angles));
114
+ case "scale":
115
+ return this.keep(this.solid(node.child, color).scale(vec3(node.factor)));
116
+ default:
117
+ return this.keep(this.solid(node.child, color).mirror(node.normal));
118
+ }
119
+ }
120
+ /** Builds a polyhedron. The build splits each face into a fan of triangles. */
121
+ polyhedron(points, faces) {
122
+ const triVerts = [];
123
+ for (const face of faces) {
124
+ for (let i = 1; i + 1 < face.length; i++)
125
+ triVerts.push(face[0], face[i], face[i + 1]);
126
+ }
127
+ const mesh = new this.m.Mesh({ numProp: 3, vertProperties: Float32Array.from(points.flat()), triVerts: Uint32Array.from(triVerts) });
128
+ let solid;
129
+ try {
130
+ solid = this.keep(this.m.Manifold.ofMesh(mesh));
131
+ }
132
+ catch (error) {
133
+ throw new RenderError("E_INPUT", `the polyhedron is not a closed solid: ${error instanceof Error ? error.message : String(error)}`);
134
+ }
135
+ if (solid.volume() < 0) {
136
+ throw new RenderError("E_INPUT", "the polyhedron faces turn inward; give each face counter-clockwise, seen from outside");
137
+ }
138
+ return solid;
139
+ }
140
+ }
141
+ /**
142
+ * Builds the solid of a checked document and returns one mesh with flat normals at sharp edges.
143
+ * The faces carry the colours of the primitives. A result over maxFacets rejects with E_LIMIT.
144
+ */
145
+ export async function buildCad(document, maxFacets) {
146
+ const m = await loadManifold();
147
+ const build = new Build(m, document.segments ?? DEFAULT_SEGMENTS, maxFacets);
148
+ try {
149
+ let solid;
150
+ try {
151
+ solid = build.solid(document.model, null);
152
+ }
153
+ catch (error) {
154
+ if (error instanceof RenderError)
155
+ throw error;
156
+ throw new RenderError("E_INPUT", `the solid operations failed: ${error instanceof Error ? error.message : String(error)}`);
157
+ }
158
+ const status = solid.status();
159
+ if (status !== "NoError") {
160
+ throw new RenderError("E_INPUT", `the solid operations failed: ${String(status)}`);
161
+ }
162
+ build.checkFacets(solid);
163
+ const shaded = build.keep(solid.calculateNormals(NORMAL_CHANNEL, SHARP_ANGLE));
164
+ const out = shaded.getMesh(NORMAL_CHANNEL);
165
+ return { mesh: toCadMesh(out, build.colors, document.model.name ?? "model"), volume: solid.volume() };
166
+ }
167
+ finally {
168
+ build.free();
169
+ }
170
+ }
171
+ /** Converts the output mesh to flat arrays. Each run of triangles from one original solid becomes one face. */
172
+ function toCadMesh(out, colors, name) {
173
+ const stride = out.numProp;
174
+ const count = out.vertProperties.length / stride;
175
+ const positions = new Float32Array(count * 3);
176
+ const normals = new Float32Array(count * 3);
177
+ for (let v = 0; v < count; v++) {
178
+ for (let c = 0; c < 3; c++) {
179
+ positions[v * 3 + c] = out.vertProperties[v * stride + c];
180
+ normals[v * 3 + c] = out.vertProperties[v * stride + NORMAL_OFFSET + c];
181
+ }
182
+ }
183
+ const faces = [];
184
+ const runIndex = out.runIndex ?? Uint32Array.from([0, out.triVerts.length]);
185
+ const runIds = out.runOriginalID ?? new Uint32Array(runIndex.length - 1);
186
+ for (let r = 0; r + 1 < runIndex.length; r++) {
187
+ const first = runIndex[r] / 3;
188
+ const last = runIndex[r + 1] / 3 - 1;
189
+ if (last < first)
190
+ continue;
191
+ faces.push({ first, last, color: colors.get(runIds[r]) ?? null });
192
+ }
193
+ return { name, positions, normals, indices: Uint32Array.from(out.triVerts), faces };
194
+ }
195
+ //# sourceMappingURL=cad-build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cad-build.js","sourceRoot":"","sources":["../../src/mesh/cad-build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { BooleanNode, CadDocument, CadStyle, CircleNode, CubeNode, CylinderNode, ExtrudeNode, MirrorNode, PolygonNode, PolyhedronNode, ProfileNode, RectangleNode, RevolveNode, RotateNode, ScaleNode, SolidNode, SphereNode, TranslateNode, Vec2, Vec3 } from "./cad-document.ts";
2
+ /** The options of a cube. */
3
+ export type CubeOptions = CadStyle & {
4
+ center?: boolean;
5
+ };
6
+ /** The options of a node with segments. */
7
+ export type RoundOptions = CadStyle & {
8
+ segments?: number;
9
+ };
10
+ /** A box. A number gives a box with equal sides. */
11
+ export declare function cube(size: number | Vec3, options?: CubeOptions): CubeNode;
12
+ /** A cylinder. Give one radius, or the bottom and the top radius for a cone. */
13
+ export declare function cylinder(height: number, radius: number | [number, number], options?: RoundOptions & {
14
+ center?: boolean;
15
+ }): CylinderNode;
16
+ /** A sphere centred on the origin. */
17
+ export declare function sphere(radius: number, options?: RoundOptions): SphereNode;
18
+ /** A closed solid from points and convex faces, counter-clockwise seen from outside. */
19
+ export declare function polyhedron(points: Vec3[], faces: number[][], options?: CadStyle): PolyhedronNode;
20
+ /** A rectangle profile. */
21
+ export declare function rectangle(size: number | Vec2, options?: CubeOptions): RectangleNode;
22
+ /** A circle profile. */
23
+ export declare function circle(radius: number, options?: RoundOptions): CircleNode;
24
+ /** A polygon profile, counter-clockwise. */
25
+ export declare function polygon(points: Vec2[], options?: CadStyle): PolygonNode;
26
+ /** The options of an extrusion. */
27
+ export type ExtrudeOptions = CadStyle & {
28
+ twist?: number;
29
+ scale?: number | Vec2;
30
+ divisions?: number;
31
+ center?: boolean;
32
+ };
33
+ /** Pulls a profile along the z axis. */
34
+ export declare function extrude(profile: ProfileNode, height: number, options?: ExtrudeOptions): ExtrudeNode;
35
+ /** Turns a profile around its y axis. */
36
+ export declare function revolve(profile: ProfileNode, options?: RoundOptions & {
37
+ degrees?: number;
38
+ }): RevolveNode;
39
+ /** The union of the solids. */
40
+ export declare function union(children: SolidNode[], options?: CadStyle): BooleanNode;
41
+ /** The first solid minus the others. */
42
+ export declare function difference(children: SolidNode[], options?: CadStyle): BooleanNode;
43
+ /** The common part of the solids. */
44
+ export declare function intersection(children: SolidNode[], options?: CadStyle): BooleanNode;
45
+ /** Moves a solid. */
46
+ export declare function translate(offset: Vec3, child: SolidNode, options?: CadStyle): TranslateNode;
47
+ /** Turns a solid about x, then y, then z, in degrees. */
48
+ export declare function rotate(angles: Vec3, child: SolidNode, options?: CadStyle): RotateNode;
49
+ /** Scales a solid. */
50
+ export declare function scale(factor: number | Vec3, child: SolidNode, options?: CadStyle): ScaleNode;
51
+ /** Reflects a solid through the plane through the origin with this normal. */
52
+ export declare function mirror(normal: Vec3, child: SolidNode, options?: CadStyle): MirrorNode;
53
+ /** Writes the document of a model. Give the result to `render` as `JSON.stringify(document)`. */
54
+ export declare function cadDocument(model: SolidNode, options?: {
55
+ segments?: number;
56
+ }): CadDocument;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The builder API: functions that write the nodes of a CAD document. A program that uses the builder functions runs in the
3
+ * caller's process. The engine receives only the document, as data.
4
+ */
5
+ /** Returns the object without the keys whose value is undefined, so the document holds only given keys. */
6
+ function compact(value) {
7
+ return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined));
8
+ }
9
+ /** A box. A number gives a box with equal sides. */
10
+ export function cube(size, options = {}) {
11
+ return compact({ type: "cube", size, ...options });
12
+ }
13
+ /** A cylinder. Give one radius, or the bottom and the top radius for a cone. */
14
+ export function cylinder(height, radius, options = {}) {
15
+ const radii = typeof radius === "number" ? { radius } : { radius1: radius[0], radius2: radius[1] };
16
+ return compact({ type: "cylinder", height, ...radii, ...options });
17
+ }
18
+ /** A sphere centred on the origin. */
19
+ export function sphere(radius, options = {}) {
20
+ return compact({ type: "sphere", radius, ...options });
21
+ }
22
+ /** A closed solid from points and convex faces, counter-clockwise seen from outside. */
23
+ export function polyhedron(points, faces, options = {}) {
24
+ return compact({ type: "polyhedron", points, faces, ...options });
25
+ }
26
+ /** A rectangle profile. */
27
+ export function rectangle(size, options = {}) {
28
+ return compact({ type: "rectangle", size, ...options });
29
+ }
30
+ /** A circle profile. */
31
+ export function circle(radius, options = {}) {
32
+ return compact({ type: "circle", radius, ...options });
33
+ }
34
+ /** A polygon profile, counter-clockwise. */
35
+ export function polygon(points, options = {}) {
36
+ return compact({ type: "polygon", points, ...options });
37
+ }
38
+ /** Pulls a profile along the z axis. */
39
+ export function extrude(profile, height, options = {}) {
40
+ return compact({ type: "extrude", height, child: profile, ...options });
41
+ }
42
+ /** Turns a profile around its y axis. */
43
+ export function revolve(profile, options = {}) {
44
+ return compact({ type: "revolve", child: profile, ...options });
45
+ }
46
+ /** The union of the solids. */
47
+ export function union(children, options = {}) {
48
+ return compact({ type: "union", children, ...options });
49
+ }
50
+ /** The first solid minus the others. */
51
+ export function difference(children, options = {}) {
52
+ return compact({ type: "difference", children, ...options });
53
+ }
54
+ /** The common part of the solids. */
55
+ export function intersection(children, options = {}) {
56
+ return compact({ type: "intersection", children, ...options });
57
+ }
58
+ /** Moves a solid. */
59
+ export function translate(offset, child, options = {}) {
60
+ return compact({ type: "translate", offset, child, ...options });
61
+ }
62
+ /** Turns a solid about x, then y, then z, in degrees. */
63
+ export function rotate(angles, child, options = {}) {
64
+ return compact({ type: "rotate", angles, child, ...options });
65
+ }
66
+ /** Scales a solid. */
67
+ export function scale(factor, child, options = {}) {
68
+ return compact({ type: "scale", factor, child, ...options });
69
+ }
70
+ /** Reflects a solid through the plane through the origin with this normal. */
71
+ export function mirror(normal, child, options = {}) {
72
+ return compact({ type: "mirror", normal, child, ...options });
73
+ }
74
+ /** Writes the document of a model. Give the result to `render` as `JSON.stringify(document)`. */
75
+ export function cadDocument(model, options = {}) {
76
+ return compact({ version: 1, model, ...options });
77
+ }
78
+ //# sourceMappingURL=cad-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cad-builder.js","sourceRoot":"","sources":["../../src/mesh/cad-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ /** A point or a size in 2D. */
2
+ export type Vec2 = [number, number];
3
+ /** A point, a size or a direction in 3D. */
4
+ export type Vec3 = [number, number, number];
5
+ /** A colour: red, green and blue, each from 0 to 1. */
6
+ export type Rgb = [number, number, number];
7
+ /** The keys that every node can carry. */
8
+ export interface CadStyle {
9
+ name?: string;
10
+ color?: Rgb;
11
+ }
12
+ /** A box with one corner at the origin, or centred on the origin. */
13
+ export interface CubeNode extends CadStyle {
14
+ type: "cube";
15
+ size: number | Vec3;
16
+ center?: boolean;
17
+ }
18
+ /** A cylinder or a cone along the z axis. Give `radius`, or `radius1` (bottom) and `radius2` (top). */
19
+ export interface CylinderNode extends CadStyle {
20
+ type: "cylinder";
21
+ height: number;
22
+ radius?: number;
23
+ radius1?: number;
24
+ radius2?: number;
25
+ center?: boolean;
26
+ segments?: number;
27
+ }
28
+ /** A sphere centred on the origin. */
29
+ export interface SphereNode extends CadStyle {
30
+ type: "sphere";
31
+ radius: number;
32
+ segments?: number;
33
+ }
34
+ /** A closed solid from points and faces. Each face is convex and counter-clockwise, seen from outside. */
35
+ export interface PolyhedronNode extends CadStyle {
36
+ type: "polyhedron";
37
+ points: Vec3[];
38
+ faces: number[][];
39
+ }
40
+ /** A rectangle with one corner at the origin, or centred on the origin. */
41
+ export interface RectangleNode extends CadStyle {
42
+ type: "rectangle";
43
+ size: number | Vec2;
44
+ center?: boolean;
45
+ }
46
+ /** A circle centred on the origin. */
47
+ export interface CircleNode extends CadStyle {
48
+ type: "circle";
49
+ radius: number;
50
+ segments?: number;
51
+ }
52
+ /** A simple polygon, counter-clockwise. */
53
+ export interface PolygonNode extends CadStyle {
54
+ type: "polygon";
55
+ points: Vec2[];
56
+ }
57
+ /** A 2D profile. Use a profile only as the child of extrude or revolve. */
58
+ export type ProfileNode = RectangleNode | CircleNode | PolygonNode;
59
+ /** A profile pulled along the z axis. */
60
+ export interface ExtrudeNode extends CadStyle {
61
+ type: "extrude";
62
+ height: number;
63
+ child: ProfileNode;
64
+ /** The twist of the top against the bottom, in degrees. */
65
+ twist?: number;
66
+ /** The scale of the top against the bottom. */
67
+ scale?: number | Vec2;
68
+ /** The number of extra layers between the bottom and the top. */
69
+ divisions?: number;
70
+ center?: boolean;
71
+ }
72
+ /** A profile turned around the y axis of the profile, which becomes the z axis of the solid. */
73
+ export interface RevolveNode extends CadStyle {
74
+ type: "revolve";
75
+ child: ProfileNode;
76
+ degrees?: number;
77
+ segments?: number;
78
+ }
79
+ /** A boolean operation. `difference` subtracts the second and later children from the first. */
80
+ export interface BooleanNode extends CadStyle {
81
+ type: "union" | "difference" | "intersection";
82
+ children: SolidNode[];
83
+ }
84
+ /** A move of a solid by an offset. */
85
+ export interface TranslateNode extends CadStyle {
86
+ type: "translate";
87
+ offset: Vec3;
88
+ child: SolidNode;
89
+ }
90
+ /** A rotation about x, then y, then z, in degrees. */
91
+ export interface RotateNode extends CadStyle {
92
+ type: "rotate";
93
+ angles: Vec3;
94
+ child: SolidNode;
95
+ }
96
+ /** A scale of a solid: one factor, or one factor per axis. */
97
+ export interface ScaleNode extends CadStyle {
98
+ type: "scale";
99
+ factor: number | Vec3;
100
+ child: SolidNode;
101
+ }
102
+ /** A reflection through the plane through the origin with this normal. */
103
+ export interface MirrorNode extends CadStyle {
104
+ type: "mirror";
105
+ normal: Vec3;
106
+ child: SolidNode;
107
+ }
108
+ /** A 3D node. */
109
+ export type SolidNode = CubeNode | CylinderNode | SphereNode | PolyhedronNode | ExtrudeNode | RevolveNode | BooleanNode | TranslateNode | RotateNode | ScaleNode | MirrorNode;
110
+ /** Any node of a CAD document. */
111
+ export type CadNode = SolidNode | ProfileNode;
112
+ /** A CAD document: data only. The engine executes no code from the document. */
113
+ export interface CadDocument {
114
+ version: 1;
115
+ model: SolidNode;
116
+ /** The default number of segments of a full circle. */
117
+ segments?: number;
118
+ }
119
+ /** The limits of one document. */
120
+ export interface CadLimits {
121
+ maxNodes: number;
122
+ maxFacets: number;
123
+ }
124
+ /** A checked document with its node count and its facet estimate. */
125
+ export interface CheckedCadDocument {
126
+ document: CadDocument;
127
+ nodes: number;
128
+ facetEstimate: number;
129
+ }
130
+ /** The default number of segments of a full circle. */
131
+ export declare const DEFAULT_SEGMENTS = 32;
132
+ /** The range of a segments value. */
133
+ export declare const MIN_SEGMENTS = 3;
134
+ export declare const MAX_SEGMENTS = 1024;
135
+ /** The facets of a sphere: the engine refines an octahedron, so the segments round up to a multiple of 4. */
136
+ export declare function sphereFacets(segments: number): number;
137
+ /** Checks a parsed document. The function rejects with E_INPUT on a bad value and with E_LIMIT over a limit. */
138
+ export declare function checkCadDocument(value: unknown, limits: CadLimits): CheckedCadDocument;
139
+ /** Parses and checks the JSON text of a CAD document. Text that is not JSON rejects with E_INPUT. */
140
+ export declare function parseCadDocument(text: string, limits: CadLimits): CheckedCadDocument;