okgeometry-api 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Mesh.d.ts +0 -32
- package/dist/Mesh.d.ts.map +1 -1
- package/dist/Mesh.js +8 -91
- package/dist/Mesh.js.map +1 -1
- package/dist/engine.d.ts +0 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +0 -37
- package/dist/engine.js.map +1 -1
- package/dist/mesh-boolean.protocol.d.ts +2 -2
- package/dist/mesh-boolean.protocol.d.ts.map +1 -1
- package/dist/wasm-base64.d.ts +1 -1
- package/dist/wasm-base64.d.ts.map +1 -1
- package/dist/wasm-base64.js +1 -1
- package/dist/wasm-base64.js.map +1 -1
- package/package.json +46 -45
- package/src/Arc.ts +117 -0
- package/src/BufferCodec.ts +181 -0
- package/src/Circle.ts +153 -0
- package/src/Geometry.ts +39 -0
- package/src/Line.ts +144 -0
- package/src/Mesh.ts +1476 -0
- package/src/NurbsCurve.ts +240 -0
- package/src/NurbsSurface.ts +267 -0
- package/src/Plane.ts +132 -0
- package/src/Point.ts +145 -0
- package/src/PolyCurve.ts +306 -0
- package/src/Polygon.ts +75 -0
- package/src/Polyline.ts +153 -0
- package/src/Ray.ts +90 -0
- package/src/Vec3.ts +159 -0
- package/src/engine.ts +92 -0
- package/src/index.ts +45 -0
- package/src/mesh-boolean.pool.ts +481 -0
- package/src/mesh-boolean.protocol.ts +122 -0
- package/src/mesh-boolean.worker.ts +160 -0
- package/src/types.ts +84 -0
- package/src/wasm-base64.ts +2 -0
- package/wasm/okgeometrycore.d.ts +19 -20
- package/wasm/okgeometrycore.js +62 -26
- package/wasm/okgeometrycore_bg.js +47 -0
- package/wasm/okgeometrycore_bg.wasm +0 -0
- package/wasm/okgeometrycore_bg.wasm.d.ts +2 -2
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { init, isInitialized } from "./engine.js";
|
|
2
|
+
import { Mesh } from "./Mesh.js";
|
|
3
|
+
import type {
|
|
4
|
+
MeshBooleanErrorPayload,
|
|
5
|
+
MeshBooleanWorkerErrorResponse,
|
|
6
|
+
MeshBooleanWorkerInbound,
|
|
7
|
+
MeshBooleanWorkerResponse,
|
|
8
|
+
MeshBooleanWorkerSuccessResponse,
|
|
9
|
+
} from "./mesh-boolean.protocol.js";
|
|
10
|
+
|
|
11
|
+
const workerScope = self as unknown as {
|
|
12
|
+
postMessage: (message: MeshBooleanWorkerResponse, transfer?: Transferable[]) => void;
|
|
13
|
+
addEventListener: (type: "message", listener: (event: MessageEvent<MeshBooleanWorkerInbound>) => void) => void;
|
|
14
|
+
};
|
|
15
|
+
const workerGlobal = globalThis as typeof globalThis & {
|
|
16
|
+
__okgeometryBooleanCancelFlag?: Int32Array | null;
|
|
17
|
+
__okgeometry_boolean_should_cancel?: () => boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const cancelledJobs = new Set<number>();
|
|
21
|
+
let initPromise: Promise<void> | null = null;
|
|
22
|
+
|
|
23
|
+
function readCancelRequested(cancelView: Int32Array | undefined): boolean {
|
|
24
|
+
if (!cancelView) return false;
|
|
25
|
+
try {
|
|
26
|
+
return (Atomics.load(cancelView, 0) | 0) !== 0;
|
|
27
|
+
} catch {
|
|
28
|
+
return (cancelView[0] | 0) !== 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isCancelled(jobId: number, cancelView: Int32Array | undefined): boolean {
|
|
33
|
+
return cancelledJobs.has(jobId) || readCancelRequested(cancelView);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
workerGlobal.__okgeometry_boolean_should_cancel = () =>
|
|
37
|
+
readCancelRequested(workerGlobal.__okgeometryBooleanCancelFlag ?? undefined);
|
|
38
|
+
|
|
39
|
+
function nowMs(): number {
|
|
40
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
41
|
+
return performance.now();
|
|
42
|
+
}
|
|
43
|
+
return Date.now();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function toErrorMessage(error: unknown): string {
|
|
47
|
+
if (error instanceof Error) return error.message;
|
|
48
|
+
if (typeof error === "string") return error;
|
|
49
|
+
return String(error);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function makeError(code: MeshBooleanErrorPayload["code"], message: string, details?: string): MeshBooleanErrorPayload {
|
|
53
|
+
return { code, message, details };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function postError(jobId: number, startedAt: number, payload: MeshBooleanErrorPayload): void {
|
|
57
|
+
const response: MeshBooleanWorkerErrorResponse = {
|
|
58
|
+
kind: "mesh-boolean-result",
|
|
59
|
+
jobId,
|
|
60
|
+
ok: false,
|
|
61
|
+
error: payload,
|
|
62
|
+
elapsedMs: Math.max(0, nowMs() - startedAt),
|
|
63
|
+
};
|
|
64
|
+
workerScope.postMessage(response);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function postSuccess(jobId: number, startedAt: number, buffer: ArrayBuffer): void {
|
|
68
|
+
const response: MeshBooleanWorkerSuccessResponse = {
|
|
69
|
+
kind: "mesh-boolean-result",
|
|
70
|
+
jobId,
|
|
71
|
+
ok: true,
|
|
72
|
+
buffer,
|
|
73
|
+
elapsedMs: Math.max(0, nowMs() - startedAt),
|
|
74
|
+
};
|
|
75
|
+
workerScope.postMessage(response, [buffer]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function ensureWorkerInit(): Promise<void> {
|
|
79
|
+
if (isInitialized()) return;
|
|
80
|
+
if (!initPromise) {
|
|
81
|
+
initPromise = init();
|
|
82
|
+
}
|
|
83
|
+
await initPromise;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
workerScope.addEventListener("message", async (event: MessageEvent<MeshBooleanWorkerInbound>) => {
|
|
87
|
+
const message = event.data;
|
|
88
|
+
if (!message) return;
|
|
89
|
+
|
|
90
|
+
if (message.kind === "mesh-boolean-cancel") {
|
|
91
|
+
cancelledJobs.add(message.jobId);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (message.kind !== "mesh-boolean-request") return;
|
|
96
|
+
const startedAt = nowMs();
|
|
97
|
+
const jobId = message.jobId;
|
|
98
|
+
const cancelView = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : undefined;
|
|
99
|
+
|
|
100
|
+
if (isCancelled(jobId, cancelView)) {
|
|
101
|
+
postError(jobId, startedAt, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
|
|
102
|
+
cancelledJobs.delete(jobId);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
await ensureWorkerInit();
|
|
108
|
+
|
|
109
|
+
if (isCancelled(jobId, cancelView)) {
|
|
110
|
+
postError(jobId, startedAt, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
|
|
111
|
+
cancelledJobs.delete(jobId);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
workerGlobal.__okgeometryBooleanCancelFlag = cancelView ?? null;
|
|
116
|
+
|
|
117
|
+
const meshA = Mesh.fromBuffer(new Float64Array(message.bufferA));
|
|
118
|
+
const meshB = Mesh.fromBuffer(new Float64Array(message.bufferB));
|
|
119
|
+
const options = {
|
|
120
|
+
allowUnsafe: message.options.allowUnsafe ?? true,
|
|
121
|
+
limits: message.options.limits,
|
|
122
|
+
backend: message.options.backend,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
let result: Mesh;
|
|
126
|
+
if (message.operation === "union") {
|
|
127
|
+
result = meshA.union(meshB, options);
|
|
128
|
+
} else if (message.operation === "subtraction") {
|
|
129
|
+
result = meshA.subtract(meshB, options);
|
|
130
|
+
} else {
|
|
131
|
+
result = meshA.intersect(meshB, options);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (isCancelled(jobId, cancelView)) {
|
|
135
|
+
postError(jobId, startedAt, makeError("worker_aborted", `Boolean ${message.operation} aborted.`));
|
|
136
|
+
cancelledJobs.delete(jobId);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const payload = new Float64Array(result.rawBuffer);
|
|
141
|
+
postSuccess(jobId, startedAt, payload.buffer);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
const details = toErrorMessage(error);
|
|
144
|
+
const cancelled = isCancelled(jobId, cancelView) || details.toLowerCase().includes("cancel");
|
|
145
|
+
postError(
|
|
146
|
+
jobId,
|
|
147
|
+
startedAt,
|
|
148
|
+
makeError(
|
|
149
|
+
cancelled ? "worker_aborted" : "kernel_error",
|
|
150
|
+
cancelled ? `Boolean ${message.operation} aborted.` : `Boolean ${message.operation} failed.`,
|
|
151
|
+
cancelled ? undefined : details,
|
|
152
|
+
),
|
|
153
|
+
);
|
|
154
|
+
} finally {
|
|
155
|
+
workerGlobal.__okgeometryBooleanCancelFlag = null;
|
|
156
|
+
cancelledJobs.delete(jobId);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
export {};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for OkGeometry API.
|
|
3
|
+
* This module consolidates types used across multiple files.
|
|
4
|
+
* @module types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Line } from "./Line.js";
|
|
8
|
+
import type { Circle } from "./Circle.js";
|
|
9
|
+
import type { Arc } from "./Arc.js";
|
|
10
|
+
import type { Polyline } from "./Polyline.js";
|
|
11
|
+
import type { Polygon } from "./Polygon.js";
|
|
12
|
+
import type { NurbsCurve } from "./NurbsCurve.js";
|
|
13
|
+
import type { PolyCurve } from "./PolyCurve.js";
|
|
14
|
+
import type { Vec3 } from "./Vec3.js";
|
|
15
|
+
|
|
16
|
+
// ── Curve Type Unions ──────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Any curve type that sweep/loft operations can accept.
|
|
20
|
+
* All these types support pointAt(), sample(), and length() methods.
|
|
21
|
+
*/
|
|
22
|
+
export type SweepableCurve =
|
|
23
|
+
| Line
|
|
24
|
+
| Circle
|
|
25
|
+
| Arc
|
|
26
|
+
| Polyline
|
|
27
|
+
| Polygon
|
|
28
|
+
| NurbsCurve
|
|
29
|
+
| PolyCurve;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Alias for SweepableCurve - any curve type that loft operations can accept.
|
|
33
|
+
* Provided for semantic clarity in loft-specific contexts.
|
|
34
|
+
*/
|
|
35
|
+
export type LoftableCurve = SweepableCurve;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Rotation axis specification.
|
|
39
|
+
* - Vec3: Rotation around axis through origin
|
|
40
|
+
* - Line: Rotation around arbitrary axis in space
|
|
41
|
+
*/
|
|
42
|
+
export type RotationAxis = Vec3 | Line;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Curve segment types used in PolyCurve.
|
|
46
|
+
* A PolyCurve is composed of sequential Line and Arc segments.
|
|
47
|
+
*/
|
|
48
|
+
export type CurveSegment = Line | Arc;
|
|
49
|
+
|
|
50
|
+
// ── WASM Buffer Encoding Constants ─────────────────────────────────
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Curve type codes for WASM buffer encoding.
|
|
54
|
+
* Used by Mesh.encodeCurve() for sweep_curves WASM function.
|
|
55
|
+
*
|
|
56
|
+
* Buffer formats:
|
|
57
|
+
* - Line (0): [0, sx,sy,sz, ex,ey,ez] - 7 floats
|
|
58
|
+
* - Circle (1): [1, cx,cy,cz, nx,ny,nz, r, ux?,uy?,uz?] - 8 or 11 floats
|
|
59
|
+
* - Arc (2): [2, cx,cy,cz, nx,ny,nz, r, startAngle, endAngle] - 10 floats
|
|
60
|
+
* - Polyline (3): [3, count, x1,y1,z1, ...] - 2 + count*3 floats
|
|
61
|
+
* - NurbsCurve (4): [4, degree, count, xyz..., weights..., knots...]
|
|
62
|
+
* - PolyCurve (5): [5, numSegs, segType, segData..., ...]
|
|
63
|
+
*/
|
|
64
|
+
export const enum CurveTypeCode {
|
|
65
|
+
Line = 0,
|
|
66
|
+
Circle = 1,
|
|
67
|
+
Arc = 2,
|
|
68
|
+
Polyline = 3,
|
|
69
|
+
NurbsCurve = 4,
|
|
70
|
+
PolyCurve = 5,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Segment type codes for PolyCurve WASM encoding.
|
|
75
|
+
* Used when encoding/decoding PolyCurve segments.
|
|
76
|
+
*
|
|
77
|
+
* Buffer formats:
|
|
78
|
+
* - Line (0): [sx,sy,sz, ex,ey,ez] - 6 floats
|
|
79
|
+
* - Arc (1): [cx,cy,cz, nx,ny,nz, r, startAngle, endAngle] - 9 floats
|
|
80
|
+
*/
|
|
81
|
+
export const enum SegmentTypeCode {
|
|
82
|
+
Line = 0,
|
|
83
|
+
Arc = 1,
|
|
84
|
+
}
|