@metamesh/modeling 0.10.0 → 0.11.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +56 -17
  3. package/dist/api/engine.d.ts +105 -8
  4. package/dist/api/index.d.ts +754 -771
  5. package/dist/engine/construction-operations.js +3 -1
  6. package/dist/engine/deferred-context.js +182 -0
  7. package/dist/engine/execution.js +38 -4
  8. package/dist/engine/finalization.js +65 -133
  9. package/dist/engine/geometry-recipes.js +12 -0
  10. package/dist/engine/immutable-generation-data.js +186 -0
  11. package/dist/engine/index.js +57 -35
  12. package/dist/engine/kernel/manifold.wasm +0 -0
  13. package/dist/engine/model-dependencies.js +46 -0
  14. package/dist/engine/model-summary.js +43 -0
  15. package/dist/engine/native/ownership.js +11 -5
  16. package/dist/engine/placement.js +24 -0
  17. package/dist/engine/recipe-realization.js +119 -0
  18. package/dist/engine/session-graph.js +442 -0
  19. package/dist/engine/session-native.js +90 -0
  20. package/dist/engine/session-snapshot.js +153 -0
  21. package/dist/engine/session.js +184 -0
  22. package/dist/engine/shape-anchors.js +5 -0
  23. package/dist/geometry/mesh-centroid.js +7 -6
  24. package/dist/geometry/mesh-planar.js +11 -10
  25. package/dist/geometry/mesh-quality.js +15 -14
  26. package/dist/geometry/mesh-signature.js +8 -7
  27. package/dist/geometry/mesh-solid.js +10 -4
  28. package/dist/geometry/mesh.js +36 -31
  29. package/dist/index.js +2 -0
  30. package/dist/model/execution-binding.js +5 -5
  31. package/dist/model/generation.js +27 -0
  32. package/dist/model/immutable-buffer.js +111 -0
  33. package/dist/model/modeling-context.js +1 -0
  34. package/dist/model/operations.js +521 -160
  35. package/dist/model/shape-handles.js +44 -0
  36. package/package.json +4 -4
@@ -1,161 +1,522 @@
1
+ import { GeometryError } from "../geometry/errors.js";
1
2
  import { currentModelContext } from "./execution-binding.js";
2
- function operation(name) {
3
- const invoke = (...args) => {
4
- const context = currentModelContext(name);
5
- const method = context[name];
6
- return Reflect.apply(method, undefined, args);
7
- };
8
- return invoke;
9
- }
10
- /** Matches an explicit profile family using the current build's physical resolution. */
11
- export const matchProfiles =
12
- /* @__PURE__ */ operation("matchProfiles");
13
- /** Copies intersections along a finite directed ray segment during the active build. */
14
- export const rayCast = /* @__PURE__ */ operation("rayCast");
15
- /**
16
- * Returns bound local operations, optionally with derived resolution, without changing imported operations.
17
- */
18
- export function modelingFunctions(resolution) {
19
- const context = currentModelContext("modelingFunctions");
20
- return resolution === undefined ? context : context.withResolution(resolution);
21
- }
22
- /** Host-bound box operation. Valid only during a synchronous build. */
23
- export const box = /* @__PURE__ */ operation("box");
24
- /** Constructs a closed rectilinear heightfield during the active synchronous build. */
25
- export const heightfield = /* @__PURE__ */ operation("heightfield");
26
- /** Returns an immutable copy with the explicit native millimetre tolerance. */
27
- export const setTolerance =
28
- /* @__PURE__ */ operation("setTolerance");
29
- /** Host-bound cylinder operation. Valid only during a synchronous build. */
30
- export const cylinder = /* @__PURE__ */ operation("cylinder");
31
- /** Host-bound tube operation. Valid only during a synchronous build. */
32
- export const tube = /* @__PURE__ */ operation("tube");
33
- /** Host-bound sphere operation. Valid only during a synchronous build. */
34
- export const sphere = /* @__PURE__ */ operation("sphere");
35
- /** Host-bound torus operation. Valid only during a synchronous build. */
36
- export const torus = /* @__PURE__ */ operation("torus");
37
- /** Host-bound union operation. Valid only during a synchronous build. */
38
- export const union = /* @__PURE__ */ operation("union");
39
- /** Host-bound subtract operation. Valid only during a synchronous build. */
40
- export const subtract = /* @__PURE__ */ operation("subtract");
41
- /** Host-bound intersect operation. Valid only during a synchronous build. */
42
- export const intersect = /* @__PURE__ */ operation("intersect");
43
- /** Returns intersection and difference with a same-build cutter, including empty results. */
44
- export const split = /* @__PURE__ */ operation("split");
45
- /** Splits a solid into the normal-side and opposite-side halves of a world-space plane. */
46
- export const splitByPlane =
47
- /* @__PURE__ */ operation("splitByPlane");
48
- /** Host-bound compose operation. Valid only during a synchronous build. */
49
- export const compose = /* @__PURE__ */ operation("compose");
50
- /** Host-bound hull operation. Valid only during a synchronous build. */
51
- export const hull = /* @__PURE__ */ operation("hull");
52
- /** Host-bound minkowskiSum operation. Valid only during a synchronous build. */
53
- export const minkowskiSum =
54
- /* @__PURE__ */ operation("minkowskiSum");
55
- /** Host-bound solidFromMesh operation. Valid only during a synchronous build. */
56
- export const solidFromMesh =
57
- /* @__PURE__ */ operation("solidFromMesh");
58
- /** Host-bound toTriangleMesh operation. Valid only during a synchronous build. */
59
- export const toTriangleMesh =
60
- /* @__PURE__ */ operation("toTriangleMesh");
61
- /** Host-bound translate operation. Valid only during a synchronous build. */
62
- export const translate = /* @__PURE__ */ operation("translate");
63
- /** Host-bound rotate operation. Valid only during a synchronous build. */
64
- export const rotate = /* @__PURE__ */ operation("rotate");
65
- /** Host-bound scale operation. Valid only during a synchronous build. */
66
- export const scale = /* @__PURE__ */ operation("scale");
67
- /** Host-bound mirror operation. Valid only during a synchronous build. */
68
- export const mirror = /* @__PURE__ */ operation("mirror");
69
- /** Host-bound transform operation. Valid only during a synchronous build. */
70
- export const transform = /* @__PURE__ */ operation("transform");
71
- /** Host-bound fromRegion operation. Valid only during a synchronous build. */
72
- export const fromRegion = /* @__PURE__ */ operation("fromRegion");
73
- /** Host-bound toRegion operation. Valid only during a synchronous build. */
74
- export const toRegion = /* @__PURE__ */ operation("toRegion");
75
- /** Host-bound rectangle operation. Valid only during a synchronous build. */
76
- export const rectangle = /* @__PURE__ */ operation("rectangle");
77
- /** Host-bound circle operation. Valid only during a synchronous build. */
78
- export const circle = /* @__PURE__ */ operation("circle");
79
- /** Host-bound regularPolygon operation. Valid only during a synchronous build. */
80
- export const regularPolygon =
81
- /* @__PURE__ */ operation("regularPolygon");
82
- /** Host-bound star operation. Valid only during a synchronous build. */
83
- export const star = /* @__PURE__ */ operation("star");
84
- /** Host-bound extrude operation. Valid only during a synchronous build. */
85
- export const extrude = /* @__PURE__ */ operation("extrude");
86
- /** Host-bound revolve operation. Valid only during a synchronous build. */
87
- export const revolve = /* @__PURE__ */ operation("revolve");
88
- /** Host-bound projectSection operation. Valid only during a synchronous build. */
89
- export const projectSection =
90
- /* @__PURE__ */ operation("projectSection");
91
- /** Host-bound sliceSection operation. Valid only during a synchronous build. */
92
- export const sliceSection =
93
- /* @__PURE__ */ operation("sliceSection");
94
- /** Host-bound loft operation. Valid only during a synchronous build. */
95
- export const loft = /* @__PURE__ */ operation("loft");
96
- /** Host-bound sweep operation. Valid only during a synchronous build. */
97
- export const sweep = /* @__PURE__ */ operation("sweep");
98
- /** Host-bound inspectSection operation. Valid only during a synchronous build. */
99
- export const inspectSection =
100
- /* @__PURE__ */ operation("inspectSection");
101
- /** Host-bound inspectSolid operation. Valid only during a synchronous build. */
102
- export const inspectSolid =
103
- /* @__PURE__ */ operation("inspectSolid");
104
- /** Tests a solid or filled section in the active build, including expected empty Boolean results. */
105
- export const isEmpty = /* @__PURE__ */ operation("isEmpty");
106
- /** Measures the minimum separation between two nonempty solids in millimetres. */
107
- export const distance = /* @__PURE__ */ operation("distance");
108
- /** Host-bound components operation. Valid only during a synchronous build. */
109
- export const components = /* @__PURE__ */ operation("components");
110
- /** Host-bound simplify operation. Valid only during a synchronous build. */
111
- export const simplify = /* @__PURE__ */ operation("simplify");
112
- /** Host-bound implicit operation. Valid only during a synchronous build. */
113
- export const implicit = /* @__PURE__ */ operation("implicit");
114
- /** Host-bound linearPattern operation. Valid only during a synchronous build. */
115
- export const linearPattern =
116
- /* @__PURE__ */ operation("linearPattern");
117
- /** Host-bound radialPattern operation. Valid only during a synchronous build. */
118
- export const radialPattern =
119
- /* @__PURE__ */ operation("radialPattern");
120
- /** Host-bound gridPattern operation. Valid only during a synchronous build. */
121
- export const gridPattern = /* @__PURE__ */ operation("gridPattern");
122
- /** Host-bound pathPattern operation. Valid only during a synchronous build. */
123
- export const pathPattern = /* @__PURE__ */ operation("pathPattern");
124
- /** Host-bound threadRidge operation. Valid only during a synchronous build. */
125
- export const threadRidge = /* @__PURE__ */ operation("threadRidge");
126
- /** Host-bound threadedRod operation. Valid only during a synchronous build. */
127
- export const threadedRod = /* @__PURE__ */ operation("threadedRod");
128
- /** Host-bound internalThreadCutter operation. Valid only during a synchronous build. */
129
- export const internalThreadCutter =
130
- /* @__PURE__ */ operation("internalThreadCutter");
131
- /** Host-bound threadedNut operation. Valid only during a synchronous build. */
132
- export const threadedNut = /* @__PURE__ */ operation("threadedNut");
133
- /** Host-bound preflightThreadedRod operation. Valid only during a synchronous build. */
134
- export const preflightThreadedRod =
135
- /* @__PURE__ */ operation("preflightThreadedRod");
136
- /** Host-bound preflightThreadedNut operation. Valid only during a synchronous build. */
137
- export const preflightThreadedNut =
138
- /* @__PURE__ */ operation("preflightThreadedNut");
139
- /** Host-bound textSection operation. Valid only during a synchronous build. */
140
- export const textSection = /* @__PURE__ */ operation("textSection");
141
- /** Host-bound svgSection operation. Valid only during a synchronous build. */
142
- export const svgSection = /* @__PURE__ */ operation("svgSection");
143
- /** Host-bound svgPathSection operation. Valid only during a synchronous build. */
144
- export const svgPathSection =
145
- /* @__PURE__ */ operation("svgPathSection");
146
- /** Host-bound attach operation. Valid only during a synchronous build. */
147
- export const attach = /* @__PURE__ */ operation("attach");
148
- /** Reads one immutable named anchor from a shape in the active build. */
149
- export const anchor = /* @__PURE__ */ operation("anchor");
150
- /** Returns a new same-build shape handle with explicit copied named anchors. */
151
- export const withAnchors = /* @__PURE__ */ operation("withAnchors");
152
- /** Host-bound sectionFromContours operation. Valid only during a synchronous build. */
153
- export const sectionFromContours =
154
- /* @__PURE__ */ operation("sectionFromContours");
155
- /** Host-bound ellipse operation. Valid only during a synchronous build. */
156
- export const ellipse = /* @__PURE__ */ operation("ellipse");
157
- /** Host-bound offset operation. Valid only during a synchronous build. */
158
- export const offset = /* @__PURE__ */ operation("offset");
159
- /** Host-bound preflightInternalThreadCutter operation. Valid only during a synchronous build. */
160
- export const preflightInternalThreadCutter =
161
- /* @__PURE__ */ operation("preflightInternalThreadCutter");
3
+ function invoke(name, args) {
4
+ const context = currentModelContext(name);
5
+ return Reflect.apply(context[name], undefined, args);
6
+ }
7
+ function requireProfile(shape, operation) {
8
+ if (typeof shape !== "object" || shape === null || !("components" in shape)) {
9
+ throw new GeometryError("INVALID_ARGUMENT", `${operation}() requires a CorrespondingProfile. Use section.${operation}() for a Section.`, { operation });
10
+ }
11
+ }
12
+ /**
13
+ * Axis-aligned box with uniform or disjoint named edge/group treatments.
14
+ *
15
+ * @example Rounded box
16
+ * ```ts
17
+ * box({ size: [30, 20, 8], treatment: { kind: "round", radius: 2 } });
18
+ * ```
19
+ */
20
+ export function box(options) {
21
+ return invoke("box", [options]);
22
+ }
23
+ /**
24
+ * +Z cylinder or frustum. Face sizing compensates polygon faceting.
25
+ *
26
+ * @example Cylinder
27
+ * ```ts
28
+ * cylinder({ height: 20, radius: 10 });
29
+ * ```
30
+ *
31
+ * @example Cone
32
+ * ```ts
33
+ * cylinder({ height: 20, radius: [10, 0] });
34
+ * ```
35
+ */
36
+ export function cylinder(options) {
37
+ return invoke("cylinder", [options]);
38
+ }
39
+ /**
40
+ * Hollow +Z tube.
41
+ *
42
+ * @example Tube
43
+ * ```ts
44
+ * tube({ height: 20, outerRadius: 10, innerRadius: 6 });
45
+ * ```
46
+ */
47
+ export function tube(options) {
48
+ return invoke("tube", [options]);
49
+ }
50
+ /**
51
+ * Origin-centered sphere.
52
+ *
53
+ * @example Sphere
54
+ * ```ts
55
+ * sphere({ diameter: 20 });
56
+ * ```
57
+ */
58
+ export function sphere(options) {
59
+ return invoke("sphere", [options]);
60
+ }
61
+ /**
62
+ * Torus around +Z.
63
+ *
64
+ * @example Torus
65
+ * ```ts
66
+ * torus({ majorRadius: 12, minorRadius: 3 });
67
+ * ```
68
+ */
69
+ export function torus(options) {
70
+ return invoke("torus", [options]);
71
+ }
72
+ export function union(solids) {
73
+ return invoke("union", [solids]);
74
+ }
75
+ export function intersect(solids) {
76
+ return invoke("intersect", [solids]);
77
+ }
78
+ /**
79
+ * Splits a solid into [inside the cutter, outside the cutter].
80
+ *
81
+ * The first result is the intersection; the second is the subtraction. The cutter itself
82
+ * is not returned. Either result may be empty or contain multiple disconnected components.
83
+ *
84
+ * @example Keep the plug and the surrounding body
85
+ * ```ts
86
+ * const body = box({ size: [30, 20, 8] });
87
+ * const cutter = cylinder({ height: 10, diameter: 8 });
88
+ * const [plug, remainder] = split(body, cutter);
89
+ * // Move the plug beside the body to show both results.
90
+ * union([plug.translate([0, -20, 0]), remainder]);
91
+ * ```
92
+ */
93
+ export function split(solid, cutter) {
94
+ return invoke("split", [solid, cutter]);
95
+ }
96
+ /**
97
+ * Splits a solid into [positive-normal side, negative side] at a world-space plane.
98
+ *
99
+ * The nonzero normal is normalized; offset is the signed distance from the origin in
100
+ * millimetres, defaulting to zero. Both cut faces are closed. Select either tuple result
101
+ * to retain one side; either result may be empty.
102
+ *
103
+ * @example Separate two halves at X = 0
104
+ * ```ts
105
+ * const body = box({ size: [30, 20, 8] });
106
+ * const [right, left] = splitByPlane(body, { normal: [1, 0, 0] });
107
+ * // The gap is only for display; the cut itself removes no material.
108
+ * union([right.translate([4, 0, 0]), left.translate([-4, 0, 0])]);
109
+ * ```
110
+ *
111
+ * @example Keep only the positive half
112
+ * ```ts
113
+ * const [right] = splitByPlane(box({ size: [30, 20, 8] }), { normal: [1, 0, 0] });
114
+ * right;
115
+ * ```
116
+ */
117
+ export function splitByPlane(solid, plane) {
118
+ return invoke("splitByPlane", [solid, plane]);
119
+ }
120
+ /** Combines disjoint components without resolving overlap. */
121
+ export function compose(solids) {
122
+ return invoke("compose", [solids]);
123
+ }
124
+ export function hull(options) {
125
+ return invoke("hull", [options]);
126
+ }
127
+ /** Three-dimensional Minkowski sum. */
128
+ export function minkowskiSum(a, b) {
129
+ return invoke("minkowskiSum", [a, b]);
130
+ }
131
+ /**
132
+ * Imports a bounded closed indexed mesh.
133
+ *
134
+ * @example Mesh import
135
+ * ```ts
136
+ * import { solidFromMesh } from "@metamesh/modeling";
137
+ * import { extrudeMesh, rectangleLoop } from "@metamesh/modeling/geometry";
138
+ *
139
+ * const mesh = extrudeMesh(rectangleLoop({ size: [20, 12] }), { height: 6 });
140
+ * solidFromMesh(mesh);
141
+ * ```
142
+ */
143
+ export function solidFromMesh(mesh) {
144
+ return invoke("solidFromMesh", [mesh]);
145
+ }
146
+ /** Copies a handle to manufacturing mesh buffers. */
147
+ export function toTriangleMesh(solid) {
148
+ return invoke("toTriangleMesh", [solid]);
149
+ }
150
+ /**
151
+ * Reads a copied, immutable named anchor from this exact active generation.
152
+ *
153
+ * @example Read the top datum
154
+ * ```ts
155
+ * const plate = box({ size: [30, 20, 6] });
156
+ * anchor(plate, "top"); // position [0, 0, 3], direction [0, 0, 1]
157
+ * ```
158
+ */
159
+ export function anchor(shape, name) {
160
+ return invoke("anchor", [shape, name]);
161
+ }
162
+ /**
163
+ * Creates a native filled section without an intermediate Region2 conversion.
164
+ */
165
+ export function sectionFromContours(contours, options) {
166
+ return invoke("sectionFromContours", [contours, options]);
167
+ }
168
+ /** Imports explicit region topology once. */
169
+ export function fromRegion(region) {
170
+ return invoke("fromRegion", [region]);
171
+ }
172
+ /** Explicit copied topology inspection; not needed for section operations. */
173
+ export function toRegion(section) {
174
+ return invoke("toRegion", [section]);
175
+ }
176
+ /**
177
+ * Filled rectangular section with uniform or independently treated corners.
178
+ *
179
+ * @example Round the corners
180
+ * ```ts
181
+ * rectangle({ size: [30, 20], treatment: { kind: "round", radius: 3 } });
182
+ * ```
183
+ */
184
+ export function rectangle(options) {
185
+ return invoke("rectangle", [options]);
186
+ }
187
+ /**
188
+ * Centered circular section.
189
+ *
190
+ * @example Size to polygon faces
191
+ * ```ts
192
+ * circle({ diameter: 12, sizing: "face" });
193
+ * ```
194
+ */
195
+ export function circle(options) {
196
+ return invoke("circle", [options]);
197
+ }
198
+ /**
199
+ * Centered elliptical section.
200
+ *
201
+ * @example Ellipse by full dimensions
202
+ * ```ts
203
+ * ellipse({ size: [30, 20] });
204
+ * ```
205
+ */
206
+ export function ellipse(options) {
207
+ return invoke("ellipse", [options]);
208
+ }
209
+ /**
210
+ * Regular polygon with a vertex on +X.
211
+ *
212
+ * @example Hexagonal section
213
+ * ```ts
214
+ * regularPolygon({ radius: 10, sides: 6, sizing: "face" });
215
+ * ```
216
+ */
217
+ export function regularPolygon(options) {
218
+ return invoke("regularPolygon", [options]);
219
+ }
220
+ /**
221
+ * Alternating outer/inner star vertices.
222
+ *
223
+ * @example Five-point section
224
+ * ```ts
225
+ * star({ outerRadius: 12, innerRadius: 6, points: 5 });
226
+ * ```
227
+ */
228
+ export function star(options) {
229
+ return invoke("star", [options]);
230
+ }
231
+ /**
232
+ * Extrudes explicit corresponding contours along +Z with degree twist and top scaling.
233
+ * Filled Sections use `section.extrude(options)`.
234
+ *
235
+ * @example Extrude
236
+ * ```ts
237
+ * import { extrude, matchProfiles } from "@metamesh/modeling";
238
+ * import { rectangleProfile } from "@metamesh/modeling/geometry";
239
+ *
240
+ * const [profile] = matchProfiles([rectangleProfile({ size: [30, 20] })]);
241
+ * extrude(profile!, { height: 8 });
242
+ * ```
243
+ */
244
+ export function extrude(shape, options) {
245
+ requireProfile(shape, "extrude");
246
+ return invoke("extrude", [shape, options]);
247
+ }
248
+ /**
249
+ * Revolves explicit corresponding radial/Z contours around +Z, with caps for partial sweeps.
250
+ * Filled Sections use `section.revolve(options)`.
251
+ *
252
+ * @example Revolve
253
+ * ```ts
254
+ * import { matchProfiles, revolve } from "@metamesh/modeling";
255
+ * import { rectangleProfile } from "@metamesh/modeling/geometry";
256
+ *
257
+ * // Contour coordinates are [radius, Z].
258
+ * const [profile] = matchProfiles([rectangleProfile({ size: [4, 16], center: false })]);
259
+ * revolve(profile!, { revolveDegrees: 270 });
260
+ * ```
261
+ */
262
+ export function revolve(shape, options) {
263
+ requireProfile(shape, "revolve");
264
+ return invoke("revolve", [shape, options]);
265
+ }
266
+ export function loft(stations, options) {
267
+ return invoke("loft", [stations, options]);
268
+ }
269
+ /** Explicit family matching on a shared physical span grid using session or operation resolution. */
270
+ export function matchProfiles(profiles, options) {
271
+ return invoke("matchProfiles", [profiles, options]);
272
+ }
273
+ /**
274
+ * Sweeps explicit corresponding contours using the selected frame policy.
275
+ * Filled Sections use `section.sweep(path, options)`.
276
+ *
277
+ * @example Sweep
278
+ * ```ts
279
+ * import { matchProfiles, sweep } from "@metamesh/modeling";
280
+ * import { rectangleProfile } from "@metamesh/modeling/geometry";
281
+ *
282
+ * const [profile] = matchProfiles([rectangleProfile({ size: [6, 3] })]);
283
+ * sweep(profile!, [[0, 0, 0], [0, 0, 15], [10, 0, 25]], {
284
+ * orientation: { kind: "transport", initialNormal: [0, 1, 0] },
285
+ * });
286
+ * ```
287
+ */
288
+ export function sweep(shape, path, options) {
289
+ requireProfile(shape, "sweep");
290
+ return invoke("sweep", [shape, path, options]);
291
+ }
292
+ /**
293
+ * Copies lightweight section measurements.
294
+ *
295
+ * @example Check filled area
296
+ * ```ts
297
+ * const facts = inspectSection(rectangle({ size: [20, 10] }));
298
+ * facts.area; // 200 mm²
299
+ * ```
300
+ */
301
+ export function inspectSection(section) {
302
+ return invoke("inspectSection", [section]);
303
+ }
304
+ /**
305
+ * Reads immutable native facts once per solid; temporary components are owned by the build.
306
+ *
307
+ * @example Check dimensions and volume
308
+ * ```ts
309
+ * const facts = inspectSolid(box({ size: [30, 20, 6] }));
310
+ * facts.volume; // 3600 mm³
311
+ * ```
312
+ */
313
+ export function inspectSolid(solid) {
314
+ return invoke("inspectSolid", [solid]);
315
+ }
316
+ /**
317
+ * Checks whether a same-session solid or filled section contains no geometry.
318
+ *
319
+ * Accepts a 3D Solid or 2D Section handle, not a finalized model or raw triangle mesh.
320
+ * Useful after a Boolean operation whose inputs may not overlap; no mesh is extracted.
321
+ *
322
+ * @example Check a missed intersection
323
+ * ```ts
324
+ * const body = box({ size: 10 });
325
+ * const distant = box({ size: 10 }).translate([30, 0, 0]);
326
+ * const empty = intersect([body, distant]);
327
+ * const missed = isEmpty(empty); // true
328
+ * ```
329
+ */
330
+ export function isEmpty(shape) {
331
+ return invoke("isEmpty", [shape]);
332
+ }
333
+ /**
334
+ * Measures the minimum separation between two nonempty solids in millimetres.
335
+ *
336
+ * Uses actual geometry, not bounding-box separation or distance between object origins.
337
+ * Contact or overlapping material returns zero, including one solid inside another.
338
+ * The kernel's search range is managed internally; the result is not capped at a caller limit.
339
+ * Empty, expired or foreign-build handles reject. Results follow native numeric precision.
340
+ *
341
+ * @example Measure the gap between two blocks
342
+ * ```ts
343
+ * const left = box({ size: 10 });
344
+ * const right = box({ size: 10 }).translate([13, 0, 0]);
345
+ * const gap = distance(left, right); // 3 mm
346
+ * ```
347
+ */
348
+ export function distance(solid, other) {
349
+ return invoke("distance", [solid, other]);
350
+ }
351
+ /** Copies intersections along the finite directed origin-to-endpoint segment. */
352
+ export function rayCast(solid, origin, endpoint) {
353
+ return invoke("rayCast", [solid, origin, endpoint]);
354
+ }
355
+ export function components(solid) {
356
+ return invoke("components", [solid]);
357
+ }
358
+ /** Bounded positive-inside implicit field constructor. */
359
+ export function implicit(options) {
360
+ return invoke("implicit", [options]);
361
+ }
362
+ /**
363
+ * Closed rectilinear top above a flat base, with uniform or explicit XY coordinates.
364
+ * Samples each grid height once; center-error triangulation also samples each cell centre.
365
+ *
366
+ * @example Heightfield
367
+ * ```ts
368
+ * heightfield({
369
+ * size: [30, 20], segments: [24, 16],
370
+ * height: ([x, y]) => 3 + Math.cos(x / 5) * Math.cos(y / 5),
371
+ * });
372
+ * ```
373
+ */
374
+ export function heightfield(options) {
375
+ return invoke("heightfield", [options]);
376
+ }
377
+ /**
378
+ * Repeats one solid along a normalized direction.
379
+ *
380
+ * @example Three copies along X
381
+ * ```ts
382
+ * linearPattern(box({ size: 4 }), { count: 3, spacing: 10 });
383
+ * ```
384
+ */
385
+ export function linearPattern(source, options) {
386
+ return invoke("linearPattern", [source, options]);
387
+ }
388
+ /**
389
+ * Repeats one solid about an axis.
390
+ *
391
+ * @example Six copies around Z
392
+ * ```ts
393
+ * const pin = cylinder({ height: 6, radius: 2 }).translate([12, 0, 0]);
394
+ * radialPattern(pin, { count: 6, axis: [0, 0, 1], angleDegrees: 60 });
395
+ * ```
396
+ */
397
+ export function radialPattern(source, options) {
398
+ return invoke("radialPattern", [source, options]);
399
+ }
400
+ /**
401
+ * XY or XYZ copies, optionally centered or placed in an explicit frame.
402
+ *
403
+ * @example Centered XY grid
404
+ * ```ts
405
+ * gridPattern(box({ size: 4 }), { count: [3, 2], spacing: [10, 10], center: true });
406
+ * ```
407
+ */
408
+ export function gridPattern(source, options) {
409
+ return invoke("gridPattern", [source, options]);
410
+ }
411
+ /**
412
+ * Physical arc-length copies along a sampled path, with optional tangent orientation.
413
+ *
414
+ * @example Copies along a bent path
415
+ * ```ts
416
+ * pathPattern(box({ size: 4 }), [[0, 0, 0], [20, 0, 0], [20, 20, 0]], { count: 5 });
417
+ * ```
418
+ */
419
+ export function pathPattern(source, path, options) {
420
+ return invoke("pathPattern", [source, path, options]);
421
+ }
422
+ /** Helical ridge mesh construction. */
423
+ export function threadRidge(options) {
424
+ return invoke("threadRidge", [options]);
425
+ }
426
+ /**
427
+ * Compensated external threaded rod.
428
+ *
429
+ * @example Threaded rod
430
+ * ```ts
431
+ * import { threadedRod } from "@metamesh/modeling";
432
+ * import { createThreadProfile } from "@metamesh/modeling/geometry";
433
+ *
434
+ * const profile = createThreadProfile({ kind: "triangular", pitch: 1.75 });
435
+ * threadedRod({ nominalMajorDiameter: 12, length: 24, profile, fit: "normal" });
436
+ * ```
437
+ */
438
+ export function threadedRod(options) {
439
+ return invoke("threadedRod", [options]);
440
+ }
441
+ /**
442
+ * Compensated internal threaded cutter.
443
+ *
444
+ * @example Internal thread
445
+ * ```ts
446
+ * import { cylinder, internalThreadCutter } from "@metamesh/modeling";
447
+ * import { createThreadProfile } from "@metamesh/modeling/geometry";
448
+ * const profile = createThreadProfile({ kind: "triangular", pitch: 1.75 });
449
+ * const body = cylinder({ diameter: 20, height: 12, center: false });
450
+ * const cutter = internalThreadCutter({ nominalMajorDiameter: 12, length: 12, profile });
451
+ * body.subtract([cutter]);
452
+ * ```
453
+ */
454
+ export function internalThreadCutter(options) {
455
+ return invoke("internalThreadCutter", [options]);
456
+ }
457
+ /**
458
+ * Compensated threaded nut.
459
+ *
460
+ * @example Threaded nut
461
+ * ```ts
462
+ * import { threadedNut } from "@metamesh/modeling";
463
+ * import { createThreadProfile } from "@metamesh/modeling/geometry";
464
+ *
465
+ * const profile = createThreadProfile({ kind: "triangular", pitch: 1.75 });
466
+ * threadedNut({ nominalMajorDiameter: 12, thickness: 8, width: 20, shape: "hex", profile, fit: "normal" });
467
+ * ```
468
+ */
469
+ export function threadedNut(options) {
470
+ return invoke("threadedNut", [options]);
471
+ }
472
+ /** Allocation-free external-thread facts. */
473
+ export function preflightThreadedRod(options) {
474
+ return invoke("preflightThreadedRod", [options]);
475
+ }
476
+ /** Allocation-free internal-thread facts. */
477
+ export function preflightInternalThreadCutter(options) {
478
+ return invoke("preflightInternalThreadCutter", [options]);
479
+ }
480
+ /** Allocation-free nut/cutter facts. */
481
+ export function preflightThreadedNut(options) {
482
+ return invoke("preflightThreadedNut", [options]);
483
+ }
484
+ /**
485
+ * Consumes a previously prepared layout; never shapes or fetches a font.
486
+ *
487
+ * @example Use a prepared text layout
488
+ * ```ts
489
+ * // Prepare the exact font and layout before entering build.
490
+ * function labelSection(layout: VectorTextLayout) {
491
+ * return textSection(layout);
492
+ * }
493
+ * ```
494
+ */
495
+ export function textSection(layout, options) {
496
+ return invoke("textSection", [layout, options]);
497
+ }
498
+ /**
499
+ * Imports bounded painted SVG document geometry.
500
+ *
501
+ * @example Import a physical SVG rectangle
502
+ * ```ts
503
+ * svgSection(
504
+ * '<svg xmlns="http://www.w3.org/2000/svg" width="30mm" height="20mm" viewBox="0 0 30 20"><rect width="30" height="20"/></svg>',
505
+ * { origin: "center" },
506
+ * );
507
+ * ```
508
+ */
509
+ export function svgSection(svg, options) {
510
+ return invoke("svgSection", [svg, options]);
511
+ }
512
+ /**
513
+ * Imports bounded filled SVG path data.
514
+ *
515
+ * @example Fill an SVG path in millimetres
516
+ * ```ts
517
+ * svgPathSection("M0 0H20V12H0Z", { origin: "center", scale: 1 });
518
+ * ```
519
+ */
520
+ export function svgPathSection(path, options) {
521
+ return invoke("svgPathSection", [path, options]);
522
+ }