const DEFAULT_MODULE_ID = "xyzbc-trt"; const DEFAULT_JOINT_COUNT = 5; const SOURCE_MODE = "source-derived-kinematics-wasm"; const SEMANTIC_BOUNDARY = "linuxcnc_kinematics_wasm_c_abi"; const DEFAULT_SDK_MODULE_URL = "../../../../wasm-port/runtime/sdk/src/linuxcnc-kinematics.js"; export async function createLinuxCncKinematicsRuntime({ moduleId = DEFAULT_MODULE_ID, moduleOptions = null, switchkinsType = 0, jointCount = DEFAULT_JOINT_COUNT, wasmRoot = null, sdkModuleUrl = DEFAULT_SDK_MODULE_URL, } = {}) { const { createLinuxCncKinematicsSdk, linuxCncKinematicsWasmFile, supportedLinuxCncKinematicsModules, } = await import(sdkModuleUrl); const wasmFile = linuxCncKinematicsWasmFile(moduleId); if (!wasmFile) { throw new Error(`unsupported LinuxCNC kinematics module: ${moduleId}`); } const resolvedModuleOptions = moduleOptions || await createDefaultModuleOptions({ wasmRoot, wasmFile }); const sdk = await createLinuxCncKinematicsSdk({ moduleId, moduleOptions: resolvedModuleOptions }); let activeSwitchkinsType = switchkinsType; let activeSwitchRc = typeof sdk.switchKinematics === "function" ? sdk.switchKinematics(switchkinsType) : 0; return { apiName: "web-rtcp-5axis-linuxcnc-kinematics-runtime", moduleId, wasmFile, supportedModules: supportedLinuxCncKinematicsModules(), loaded: true, sourceMode: SOURCE_MODE, semanticBoundary: SEMANTIC_BOUNDARY, executionContext: "direct", get switchkinsType() { return activeSwitchkinsType; }, get switchRc() { return activeSwitchRc; }, jointCount, sdk, readiness() { return { apiName: "web-rtcp-5axis-linuxcnc-kinematics-runtime-readiness", moduleId, wasmFile, supportedModules: supportedLinuxCncKinematicsModules(), loaded: true, sourceMode: SOURCE_MODE, semanticBoundary: SEMANTIC_BOUNDARY, executionContext: "direct", switchkinsType: activeSwitchkinsType, switchRc: activeSwitchRc, }; }, switchKinematics(nextSwitchkinsType) { const requestedType = Number(nextSwitchkinsType) || 0; activeSwitchRc = typeof sdk.switchKinematics === "function" ? sdk.switchKinematics(requestedType) : 0; activeSwitchkinsType = requestedType; return activeSwitchRc; }, forward(joints, options = {}) { return sdk.forward(joints, options); }, inverse(pose, count = jointCount, options = {}) { return sdk.inverse(pose, count, options); }, frameForJoints(joints, options = {}) { const jointValues = Array.from(joints, Number); const forward = sdk.forward(jointValues, options.forwardOptions || {}); const inverse = sdk.inverse( forward.pose, options.jointCount || jointCount, { seedJoints: jointValues, ...(options.inverseOptions || {}) }, ); return { moduleId, switchkinsType: activeSwitchkinsType, forward, inverse, }; }, }; } async function createDefaultModuleOptions({ wasmRoot, wasmFile }) { const quietOptions = { print() {}, printErr() {}, }; if (!isNodeRuntime()) { return quietOptions; } const [{ readFileSync }, { dirname, resolve }, { fileURLToPath }] = await Promise.all([ import("node:fs"), import("node:path"), import("node:url"), ]); const moduleDir = dirname(fileURLToPath(import.meta.url)); const resolvedWasmRoot = wasmRoot || resolve(moduleDir, "../../../../wasm-port/build/wasm/kinematics"); return { ...quietOptions, wasmBinary: readFileSync(resolve(resolvedWasmRoot, wasmFile)), }; } function isNodeRuntime() { return typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string" && process.type !== "renderer"; } export function createLinuxCncKinematicsRuntimeDescriptor(runtime) { if (!runtime?.loaded) return null; return { apiName: runtime.apiName, moduleId: runtime.moduleId, wasmFile: runtime.wasmFile, supportedModules: runtime.supportedModules, loaded: runtime.loaded, sourceMode: runtime.sourceMode, semanticBoundary: runtime.semanticBoundary, executionContext: runtime.executionContext || "direct", workerUrl: runtime.workerUrl || null, switchkinsType: runtime.switchkinsType, switchRc: runtime.switchRc, }; }