okgeometry-api 1.26.1 → 1.27.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 (99) hide show
  1. package/dist/Arc.js +1 -1
  2. package/dist/Arc.js.map +1 -1
  3. package/dist/Brep.js +1 -1
  4. package/dist/Brep.js.map +1 -1
  5. package/dist/Circle.js +1 -1
  6. package/dist/Circle.js.map +1 -1
  7. package/dist/Line.js +1 -1
  8. package/dist/Line.js.map +1 -1
  9. package/dist/Mesh.d.ts +41 -0
  10. package/dist/Mesh.d.ts.map +1 -1
  11. package/dist/Mesh.js +235 -21
  12. package/dist/Mesh.js.map +1 -1
  13. package/dist/MeshSurface.js +1 -1
  14. package/dist/MeshSurface.js.map +1 -1
  15. package/dist/NurbsCurve.js +1 -1
  16. package/dist/NurbsCurve.js.map +1 -1
  17. package/dist/NurbsSurface.js +1 -1
  18. package/dist/NurbsSurface.js.map +1 -1
  19. package/dist/PolyCurve.js +1 -1
  20. package/dist/PolyCurve.js.map +1 -1
  21. package/dist/Polyline.js +1 -1
  22. package/dist/Polyline.js.map +1 -1
  23. package/dist/Ray.js +1 -1
  24. package/dist/Ray.js.map +1 -1
  25. package/dist/SculptSession.js +1 -1
  26. package/dist/SculptSession.js.map +1 -1
  27. package/dist/engine-threaded.d.ts +2 -0
  28. package/dist/engine-threaded.d.ts.map +1 -0
  29. package/dist/engine-threaded.js +33 -0
  30. package/dist/engine-threaded.js.map +1 -0
  31. package/dist/engine.d.ts +21 -0
  32. package/dist/engine.d.ts.map +1 -1
  33. package/dist/engine.js +42 -0
  34. package/dist/engine.js.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/mesh-boolean.pool.d.ts +23 -1
  40. package/dist/mesh-boolean.pool.d.ts.map +1 -1
  41. package/dist/mesh-boolean.pool.js +97 -12
  42. package/dist/mesh-boolean.pool.js.map +1 -1
  43. package/dist/mesh-boolean.protocol.d.ts +21 -1
  44. package/dist/mesh-boolean.protocol.d.ts.map +1 -1
  45. package/dist/mesh-boolean.protocol.js.map +1 -1
  46. package/dist/mesh-boolean.worker.d.ts.map +1 -1
  47. package/dist/mesh-boolean.worker.js +94 -1
  48. package/dist/mesh-boolean.worker.js.map +1 -1
  49. package/dist/wasm-active.d.ts +20 -0
  50. package/dist/wasm-active.d.ts.map +1 -0
  51. package/dist/wasm-active.js +26 -0
  52. package/dist/wasm-active.js.map +1 -0
  53. package/dist/wasm-base64-threaded.d.ts +2 -0
  54. package/dist/wasm-base64-threaded.d.ts.map +1 -0
  55. package/dist/wasm-base64-threaded.js +3 -0
  56. package/dist/wasm-base64-threaded.js.map +1 -0
  57. package/dist/wasm-base64.d.ts +1 -1
  58. package/dist/wasm-base64.d.ts.map +1 -1
  59. package/dist/wasm-base64.js +1 -1
  60. package/dist/wasm-base64.js.map +1 -1
  61. package/dist/wasm-bindings-threaded.d.ts +2664 -0
  62. package/dist/wasm-bindings-threaded.d.ts.map +1 -0
  63. package/dist/wasm-bindings-threaded.js +5008 -0
  64. package/dist/wasm-bindings-threaded.js.map +1 -0
  65. package/dist/wasm-bindings.d.ts +130 -0
  66. package/dist/wasm-bindings.d.ts.map +1 -1
  67. package/dist/wasm-bindings.js +208 -0
  68. package/dist/wasm-bindings.js.map +1 -1
  69. package/dist/workerHelpers-threaded.d.ts +2 -0
  70. package/dist/workerHelpers-threaded.d.ts.map +1 -0
  71. package/dist/workerHelpers-threaded.js +100 -0
  72. package/dist/workerHelpers-threaded.js.map +1 -0
  73. package/package.json +8 -3
  74. package/src/Arc.ts +117 -117
  75. package/src/Brep.ts +1 -1
  76. package/src/Circle.ts +166 -166
  77. package/src/Line.ts +171 -171
  78. package/src/Mesh.ts +300 -45
  79. package/src/MeshSurface.ts +1 -1
  80. package/src/NurbsCurve.ts +655 -655
  81. package/src/NurbsSurface.ts +721 -721
  82. package/src/PolyCurve.ts +203 -203
  83. package/src/Polyline.ts +316 -316
  84. package/src/Ray.ts +90 -90
  85. package/src/SculptSession.ts +377 -377
  86. package/src/engine-threaded.ts +39 -0
  87. package/src/engine.ts +46 -0
  88. package/src/index.ts +1 -1
  89. package/src/mesh-boolean.pool.ts +208 -86
  90. package/src/mesh-boolean.protocol.ts +44 -1
  91. package/src/mesh-boolean.worker.ts +170 -56
  92. package/src/wasm-active.ts +31 -0
  93. package/src/wasm-base64-threaded.ts +2 -0
  94. package/src/wasm-base64.ts +1 -1
  95. package/src/wasm-bindings-threaded.d.ts +1989 -0
  96. package/src/wasm-bindings-threaded.js +5235 -0
  97. package/src/wasm-bindings.d.ts +104 -0
  98. package/src/wasm-bindings.js +225 -0
  99. package/src/workerHelpers-threaded.js +107 -0
@@ -1,5 +1,6 @@
1
1
  import { init, isInitialized } from "./engine.js";
2
- import { Mesh } from "./Mesh.js";
2
+ import { Mesh } from "./Mesh.js";
3
+ import { Point } from "./Point.js";
3
4
  import type {
4
5
  MeshBooleanErrorPayload,
5
6
  MeshBooleanWorkerErrorResponse,
@@ -33,8 +34,8 @@ function isCancelled(jobId: number, cancelView: Int32Array | undefined): boolean
33
34
  return cancelledJobs.has(jobId) || readCancelRequested(cancelView);
34
35
  }
35
36
 
36
- workerGlobal.__okgeometry_boolean_should_cancel = () =>
37
- readCancelRequested(workerGlobal.__okgeometryBooleanCancelFlag ?? undefined);
37
+ workerGlobal.__okgeometry_boolean_should_cancel = () =>
38
+ readCancelRequested(workerGlobal.__okgeometryBooleanCancelFlag ?? undefined);
38
39
 
39
40
  function toErrorMessage(error: unknown): string {
40
41
  if (error instanceof Error) return error.message;
@@ -46,25 +47,97 @@ function makeError(code: MeshBooleanErrorPayload["code"], message: string, detai
46
47
  return { code, message, details };
47
48
  }
48
49
 
49
- function postError(jobId: number, payload: MeshBooleanErrorPayload): void {
50
- const response: MeshBooleanWorkerErrorResponse = {
51
- kind: "mesh-boolean-result",
52
- jobId,
53
- ok: false,
54
- error: payload,
55
- };
56
- workerScope.postMessage(response);
57
- }
58
-
59
- function postSuccess(jobId: number, buffer: ArrayBuffer): void {
60
- const response: MeshBooleanWorkerSuccessResponse = {
61
- kind: "mesh-boolean-result",
62
- jobId,
63
- ok: true,
64
- buffer,
65
- };
66
- workerScope.postMessage(response, [buffer]);
67
- }
50
+ function postError(jobId: number, payload: MeshBooleanErrorPayload): void {
51
+ const response: MeshBooleanWorkerErrorResponse = {
52
+ kind: "mesh-boolean-result",
53
+ jobId,
54
+ ok: false,
55
+ error: payload,
56
+ };
57
+ workerScope.postMessage(response);
58
+ }
59
+
60
+ function postSuccess(
61
+ jobId: number,
62
+ buffer: ArrayBuffer,
63
+ meta?: Record<string, string | number | boolean>,
64
+ ): void {
65
+ const response: MeshBooleanWorkerSuccessResponse = {
66
+ kind: "mesh-boolean-result",
67
+ jobId,
68
+ ok: true,
69
+ buffer,
70
+ meta,
71
+ };
72
+ workerScope.postMessage(response, [buffer]);
73
+ }
74
+
75
+ /** Heavy kernel jobs (KERNEL-PERF-ARC lever 4) — see protocol for shapes. */
76
+ function runHeavyOperation(message: {
77
+ operation: string;
78
+ buffers: ArrayBuffer[];
79
+ trusted?: boolean[];
80
+ params?: { resolution?: number; iso?: number; distance?: number };
81
+ options: { allowUnsafe?: boolean; limits?: unknown; debugForceFaceID?: boolean };
82
+ }): { buffer: ArrayBuffer; meta?: Record<string, string | number | boolean> } {
83
+ const meshes = () =>
84
+ message.buffers.map((buf, i) =>
85
+ Mesh.fromBuffer(new Float64Array(buf), {
86
+ trustedBooleanInput: message.trusted?.[i],
87
+ }),
88
+ );
89
+ const options = {
90
+ allowUnsafe: message.options.allowUnsafe ?? true,
91
+ limits: message.options.limits as never,
92
+ debugForceFaceID: message.options.debugForceFaceID,
93
+ };
94
+ const params = message.params ?? {};
95
+
96
+ switch (message.operation) {
97
+ case "unionAll": {
98
+ const result = Mesh.unionAll(meshes(), options);
99
+ return { buffer: new Float64Array(result.rawBuffer).buffer };
100
+ }
101
+ case "differenceAll": {
102
+ const [host, ...cutters] = meshes();
103
+ const result = host.subtractAll(cutters, options);
104
+ return { buffer: new Float64Array(result.rawBuffer).buffer };
105
+ }
106
+ case "makeWatertight": {
107
+ const [mesh] = meshes();
108
+ const r = mesh.makeWatertight({
109
+ resolution: params.resolution,
110
+ iso: params.iso,
111
+ });
112
+ return {
113
+ buffer: new Float64Array(r.mesh.rawBuffer).buffer,
114
+ meta: { method: r.method, effectiveResolution: r.effectiveResolution },
115
+ };
116
+ }
117
+ case "voxelRemesh": {
118
+ const [mesh] = meshes();
119
+ const result = mesh.voxelRemesh(params.resolution ?? 0, params.iso ?? 0.5);
120
+ return { buffer: new Float64Array(result.rawBuffer).buffer };
121
+ }
122
+ case "chamferEdges": {
123
+ const mesh = Mesh.fromBuffer(new Float64Array(message.buffers[0]), {
124
+ trustedBooleanInput: message.trusted?.[0],
125
+ });
126
+ const flat = new Float64Array(message.buffers[1]);
127
+ const edges: Array<{ a: Point; b: Point }> = [];
128
+ for (let i = 0; i + 5 < flat.length; i += 6) {
129
+ edges.push({
130
+ a: new Point(flat[i], flat[i + 1], flat[i + 2]),
131
+ b: new Point(flat[i + 3], flat[i + 4], flat[i + 5]),
132
+ });
133
+ }
134
+ const result = mesh.chamferEdges(edges, params.distance ?? 0);
135
+ return { buffer: new Float64Array(result.rawBuffer).buffer };
136
+ }
137
+ default:
138
+ throw new Error(`Unknown heavy operation: ${message.operation}`);
139
+ }
140
+ }
68
141
 
69
142
  async function ensureWorkerInit(): Promise<void> {
70
143
  if (isInitialized()) return;
@@ -82,25 +155,66 @@ workerScope.addEventListener("message", async (event: MessageEvent<MeshBooleanWo
82
155
  cancelledJobs.add(message.jobId);
83
156
  return;
84
157
  }
85
-
86
- if (message.kind !== "mesh-boolean-request") return;
87
- const jobId = message.jobId;
88
- const cancelView = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : undefined;
89
-
90
- if (isCancelled(jobId, cancelView)) {
91
- postError(jobId, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
92
- cancelledJobs.delete(jobId);
93
- return;
94
- }
158
+
159
+ if (message.kind === "mesh-heavy-request") {
160
+ const jobId = message.jobId;
161
+ const cancelView = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : undefined;
162
+ if (isCancelled(jobId, cancelView)) {
163
+ postError(jobId, makeError("worker_aborted", `${message.operation} aborted.`));
164
+ cancelledJobs.delete(jobId);
165
+ return;
166
+ }
167
+ try {
168
+ await ensureWorkerInit();
169
+ if (isCancelled(jobId, cancelView)) {
170
+ postError(jobId, makeError("worker_aborted", `${message.operation} aborted.`));
171
+ cancelledJobs.delete(jobId);
172
+ return;
173
+ }
174
+ workerGlobal.__okgeometryBooleanCancelFlag = cancelView ?? null;
175
+ const { buffer, meta } = runHeavyOperation(message);
176
+ if (isCancelled(jobId, cancelView)) {
177
+ postError(jobId, makeError("worker_aborted", `${message.operation} aborted.`));
178
+ cancelledJobs.delete(jobId);
179
+ return;
180
+ }
181
+ postSuccess(jobId, buffer, meta);
182
+ } catch (error) {
183
+ const details = toErrorMessage(error);
184
+ const cancelled = isCancelled(jobId, cancelView) || details.toLowerCase().includes("cancel");
185
+ postError(
186
+ jobId,
187
+ makeError(
188
+ cancelled ? "worker_aborted" : "kernel_error",
189
+ cancelled ? `${message.operation} aborted.` : `${message.operation} failed.`,
190
+ cancelled ? undefined : details,
191
+ ),
192
+ );
193
+ } finally {
194
+ workerGlobal.__okgeometryBooleanCancelFlag = null;
195
+ cancelledJobs.delete(jobId);
196
+ }
197
+ return;
198
+ }
199
+
200
+ if (message.kind !== "mesh-boolean-request") return;
201
+ const jobId = message.jobId;
202
+ const cancelView = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : undefined;
203
+
204
+ if (isCancelled(jobId, cancelView)) {
205
+ postError(jobId, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
206
+ cancelledJobs.delete(jobId);
207
+ return;
208
+ }
95
209
 
96
210
  try {
97
- await ensureWorkerInit();
98
-
99
- if (isCancelled(jobId, cancelView)) {
100
- postError(jobId, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
101
- cancelledJobs.delete(jobId);
102
- return;
103
- }
211
+ await ensureWorkerInit();
212
+
213
+ if (isCancelled(jobId, cancelView)) {
214
+ postError(jobId, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
215
+ cancelledJobs.delete(jobId);
216
+ return;
217
+ }
104
218
 
105
219
  workerGlobal.__okgeometryBooleanCancelFlag = cancelView ?? null;
106
220
 
@@ -124,23 +238,23 @@ workerScope.addEventListener("message", async (event: MessageEvent<MeshBooleanWo
124
238
  } else {
125
239
  result = meshA.intersect(meshB, options);
126
240
  }
127
-
128
- if (isCancelled(jobId, cancelView)) {
129
- postError(jobId, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
130
- cancelledJobs.delete(jobId);
131
- return;
132
- }
133
-
134
- const payload = new Float64Array(result.rawBuffer);
135
- postSuccess(jobId, payload.buffer);
136
- } catch (error) {
137
- const details = toErrorMessage(error);
138
- const cancelled = isCancelled(jobId, cancelView) || details.toLowerCase().includes("cancel");
139
- postError(
140
- jobId,
141
- makeError(
142
- cancelled ? "worker_aborted" : "kernel_error",
143
- cancelled ? `Boolean ${message.operation} aborted.` : `Boolean ${message.operation} failed.`,
241
+
242
+ if (isCancelled(jobId, cancelView)) {
243
+ postError(jobId, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
244
+ cancelledJobs.delete(jobId);
245
+ return;
246
+ }
247
+
248
+ const payload = new Float64Array(result.rawBuffer);
249
+ postSuccess(jobId, payload.buffer);
250
+ } catch (error) {
251
+ const details = toErrorMessage(error);
252
+ const cancelled = isCancelled(jobId, cancelView) || details.toLowerCase().includes("cancel");
253
+ postError(
254
+ jobId,
255
+ makeError(
256
+ cancelled ? "worker_aborted" : "kernel_error",
257
+ cancelled ? `Boolean ${message.operation} aborted.` : `Boolean ${message.operation} failed.`,
144
258
  cancelled ? undefined : details,
145
259
  ),
146
260
  );
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Mutable indirection over the active wasm bindings module
3
+ * (KERNEL-PERF-ARC lever 3).
4
+ *
5
+ * The engine ships two artifacts with an identical export surface: the
6
+ * standard single-thread build and an optional rayon-threaded build
7
+ * (atomics + shared memory) loaded only on cross-origin-isolated pages.
8
+ * All geometry classes call through `wasm` here, which resolves to the
9
+ * active module at call time; `initThreads()` swaps the module BEFORE any
10
+ * geometry exists (enforced in engine.ts), so per-instance state (stored
11
+ * meshes, sculpt sessions) never spans instances.
12
+ */
13
+ import * as standard from "./wasm-bindings.js";
14
+
15
+ type WasmModule = typeof standard;
16
+
17
+ let active: WasmModule = standard;
18
+
19
+ export function setActiveWasmModule(module: WasmModule): void {
20
+ active = module;
21
+ }
22
+
23
+ export function getActiveWasmModule(): WasmModule {
24
+ return active;
25
+ }
26
+
27
+ /** Property access resolves through the ACTIVE module at call time. */
28
+ export const wasm: WasmModule = new Proxy(Object.create(null) as WasmModule, {
29
+ get: (_target, key) => (active as unknown as Record<PropertyKey, unknown>)[key],
30
+ has: (_target, key) => key in (active as object),
31
+ });