@meshioplusplus/wasm 10.21.1 → 12.0.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.
- package/README.md +1 -1
- package/dist/meshioplusplus_wasm.mjs +1 -1
- package/dist/meshioplusplus_wasm.wasm +0 -0
- package/dist/meshioplusplus_wasm_mt.mjs +1 -1
- package/dist/meshioplusplus_wasm_mt.wasm +0 -0
- package/index.d.ts +631 -53
- package/package.json +2 -2
- package/src/index.mjs +391 -48
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshioplusplus/wasm",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "meshio++ mesh I/O compiled to WebAssembly: read
|
|
3
|
+
"version": "12.0.0",
|
|
4
|
+
"description": "meshio++ mesh I/O compiled to WebAssembly: read 43 and write 46 mesh formats (incl. MED, CGNS, Exodus) in the browser or Node.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.mjs",
|
|
7
7
|
"module": "./src/index.mjs",
|
package/src/index.mjs
CHANGED
|
@@ -30,6 +30,24 @@
|
|
|
30
30
|
// bundlers (Vite) emit both chunks. Callers can force a build with the
|
|
31
31
|
// `{ variant }` option.
|
|
32
32
|
|
|
33
|
+
// The raw xdmfSeriesWriteDataArrays embind call still converts every value
|
|
34
|
+
// with emscripten::convertJSArrayToNumberVector<double>, which throws on a
|
|
35
|
+
// BigInt64Array/BigUint64Array element (a JS `bigint` does not implicitly
|
|
36
|
+
// convert to `double`). Since data arrays now carry their source dtype
|
|
37
|
+
// (point_data/cell_data read off a mesh may be BigInt-backed), widen those to
|
|
38
|
+
// plain Float64-representable arrays here rather than in every caller.
|
|
39
|
+
function toDoubleConvertible(rArr) {
|
|
40
|
+
return rArr instanceof BigInt64Array || rArr instanceof BigUint64Array
|
|
41
|
+
? Array.from(rArr, Number)
|
|
42
|
+
: rArr;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function widenBigIntArrays(rObj) {
|
|
46
|
+
const out = {};
|
|
47
|
+
for (const [name, arr] of Object.entries(rObj)) out[name] = toDoubleConvertible(arr);
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
33
51
|
/**
|
|
34
52
|
* Decide which native artifact to load.
|
|
35
53
|
* @param {'auto'|'mt'|'seq'} variant
|
|
@@ -43,6 +61,35 @@ function resolveVariant(variant) {
|
|
|
43
61
|
return crossOriginIsolated ? 'mt' : 'seq';
|
|
44
62
|
}
|
|
45
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Thrown by `loadMeshioPlusPlus()` when a WASM module fails to instantiate,
|
|
66
|
+
* so a caller can tell a wrong `.wasm` URL from an environment that cannot
|
|
67
|
+
* run Wasm threads from a plain network failure, instead of catching a bare
|
|
68
|
+
* Emscripten abort. See doc/wasm.md's "Loading" section.
|
|
69
|
+
*/
|
|
70
|
+
export class MeshioPlusPlusLoadError extends Error {
|
|
71
|
+
/**
|
|
72
|
+
* @param {string} message
|
|
73
|
+
* @param {object} details
|
|
74
|
+
* @param {'mt'|'seq'} details.variant - which artifact was being loaded.
|
|
75
|
+
* @param {string} details.glue - the glue module specifier (e.g.
|
|
76
|
+
* '../dist/meshioplusplus_wasm_mt.mjs').
|
|
77
|
+
* @param {string} [details.requestedFile] - the filename Emscripten asked
|
|
78
|
+
* `locateFile` to resolve, if it got that far.
|
|
79
|
+
* @param {string} [details.resolvedUrl] - what `locateFile` returned for it.
|
|
80
|
+
* @param {unknown} [details.cause] - the underlying error/abort reason.
|
|
81
|
+
*/
|
|
82
|
+
constructor(message, { variant, glue, requestedFile, resolvedUrl, cause }) {
|
|
83
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
84
|
+
this.name = 'MeshioPlusPlusLoadError';
|
|
85
|
+
this.variant = variant;
|
|
86
|
+
this.glue = glue;
|
|
87
|
+
this.requestedFile = requestedFile;
|
|
88
|
+
this.resolvedUrl = resolvedUrl;
|
|
89
|
+
this.cause = cause;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
46
93
|
/**
|
|
47
94
|
* A rectangular (uniform node count) group of cells.
|
|
48
95
|
* @typedef {Object} RectangularCellBlock
|
|
@@ -90,27 +137,60 @@ function resolveVariant(variant) {
|
|
|
90
137
|
* @property {() => void} close - finalize (if needed) and release the handle.
|
|
91
138
|
*/
|
|
92
139
|
|
|
140
|
+
/**
|
|
141
|
+
* A single sequence entry: one step of one file. See {@link SequenceReader}.
|
|
142
|
+
* @typedef {Object} SequenceEntry
|
|
143
|
+
* @property {string} path
|
|
144
|
+
* @property {number} step
|
|
145
|
+
* @property {number} time
|
|
146
|
+
* @property {'explicit'|'file'|'filename'|'index'} timeSource
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @typedef {Object} SequenceReader
|
|
151
|
+
* @property {number} count
|
|
152
|
+
* @property {(i: number) => string} path
|
|
153
|
+
* @property {(i: number) => number} step
|
|
154
|
+
* @property {(i: number) => number} time
|
|
155
|
+
* @property {(i: number) => ('explicit'|'file'|'filename'|'index')} timeSource
|
|
156
|
+
* @property {(i: number) => SequenceEntry} entry
|
|
157
|
+
* @property {() => SequenceEntry[]} entries
|
|
158
|
+
* @property {(i: number, options?: {pointsOnly?: boolean, arrays?: string[]|null, lenient?: boolean}) => Mesh} read
|
|
159
|
+
* @property {() => void} close - release the handle; safe to call twice.
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* A point_data/cell_data/field_data array's JS type: it carries its source
|
|
164
|
+
* dtype crossing the WASM boundary rather than always widening to
|
|
165
|
+
* Float64Array (dtype carry, v11.2.0).
|
|
166
|
+
* @typedef {Float32Array|Float64Array|Int8Array|Int16Array|Int32Array|BigInt64Array|Uint8Array|Uint16Array|Uint32Array|BigUint64Array} DataArray
|
|
167
|
+
*/
|
|
168
|
+
|
|
93
169
|
/**
|
|
94
170
|
* @typedef {Object} Mesh
|
|
95
171
|
* @property {Float64Array} points - flat, row-major (numPoints * dim).
|
|
96
172
|
* @property {number} dim - 2 or 3.
|
|
97
173
|
* @property {CellBlock[]} cells
|
|
98
|
-
* @property {Object<string,
|
|
174
|
+
* @property {Object<string, DataArray>} [point_data]
|
|
99
175
|
* @property {Object<string, number>} [point_data_components] - per-entity width of any non-scalar point_data array, since a flat typed array carries no shape; absent name = 1 component.
|
|
100
|
-
* @property {Object<string,
|
|
176
|
+
* @property {Object<string, DataArray[]>} [cell_data] - one array per cell block, same order as `cells`; every block of one named array shares the same DataArray class.
|
|
101
177
|
* @property {Object<string, number>} [cell_data_components] - per-entity width of any non-scalar cell_data array (one value per array, not per block).
|
|
102
|
-
* @property {Object<string,
|
|
178
|
+
* @property {Object<string, DataArray>} [field_data]
|
|
103
179
|
* @property {Object<string, number>} [field_data_components] - per-entity width of any non-scalar field_data array.
|
|
180
|
+
* @property {Array<{name: string, kind: string, dim: number, tag: number, entries: Int32Array}>} [regions] - named point/cell/side groups, see doc/regions.md.
|
|
181
|
+
* @property {Array<{id: number, values: Array<{key: string, values: Float64Array, text: string, isTable: boolean, components?: number}>}>} [propertySets] - `Begin Properties` blocks (currently MDPA only), see doc/wasm.md.
|
|
104
182
|
*/
|
|
105
183
|
|
|
106
184
|
/**
|
|
107
185
|
* Instantiate a fresh meshio++ WASM module.
|
|
108
186
|
*
|
|
109
187
|
* @param {object} [moduleOverrides] - forwarded to the Emscripten module
|
|
110
|
-
* factory
|
|
111
|
-
*
|
|
112
|
-
* `locateFile
|
|
113
|
-
*
|
|
188
|
+
* factory (with `locateFile`/`onAbort` wrapped for diagnostics -- see
|
|
189
|
+
* {@link MeshioPlusPlusLoadError} -- your own overrides still run first).
|
|
190
|
+
* `{ locateFile: (p) => new URL(p, import.meta.url) }` relocates the
|
|
191
|
+
* `.wasm` binary for a bundler/CDN setup; `locateFile` receives the
|
|
192
|
+
* requested filename, so return the URL matching the loaded variant
|
|
193
|
+
* (`meshioplusplus_wasm.wasm` or `_wasm_mt.wasm`).
|
|
114
194
|
* @param {object} [options]
|
|
115
195
|
* @param {'auto'|'mt'|'seq'} [options.variant='auto'] - which native artifact to
|
|
116
196
|
* load. `auto` picks the threaded (`mt`) build under Node and in a
|
|
@@ -119,11 +199,11 @@ function resolveVariant(variant) {
|
|
|
119
199
|
* @returns {Promise<{
|
|
120
200
|
* FS: object,
|
|
121
201
|
* readMesh: (path: string, format?: string) => Mesh,
|
|
122
|
-
* readMeshSelective: (path: string, options?: {format?: string, pointsOnly?: boolean, arrays?: string[], timeStep?: number, lenient?: boolean}) => Mesh,
|
|
202
|
+
* readMeshSelective: (path: string, options?: {format?: string, pointsOnly?: boolean, arrays?: string[], timeStep?: number, lenient?: boolean, info?: boolean}) => Mesh,
|
|
123
203
|
* readMetadata: (path: string, format?: string) => object,
|
|
124
204
|
* readerSupportsOptions: (format: string) => boolean,
|
|
125
|
-
* writeMesh: (path: string, mesh: Mesh, format?: string) =>
|
|
126
|
-
* convert: (inPath: string, outPath: string, options?: {inFormat?: string, outFormat?: string}) =>
|
|
205
|
+
* writeMesh: (path: string, mesh: Mesh, format?: string, options?: {encoding?: string, codec?: string, floatFormat?: string, info?: object}) => string[],
|
|
206
|
+
* convert: (inPath: string, outPath: string, options?: {inFormat?: string, outFormat?: string, encoding?: string, codec?: string, floatFormat?: string}) => string[],
|
|
127
207
|
* convertSurface: (inPath: string, outPath: string, options?: {inFormat?: string, outFormat?: string}) => void,
|
|
128
208
|
* convertSurfaceOps: (inPath: string, outPath: string, ops?: object[], options?: {inFormat?: string, outFormat?: string, keepProvenance?: boolean}) => {steps: object[], warnings: string[]},
|
|
129
209
|
* runPipeline: (settings: object|string) => {steps: object[], warnings: string[]},
|
|
@@ -144,13 +224,16 @@ function resolveVariant(variant) {
|
|
|
144
224
|
* computeBandwidth: (mesh: Mesh) => number,
|
|
145
225
|
* diff: (a: Mesh, b: Mesh, atol?: number, rtol?: number, unordered?: boolean) => object,
|
|
146
226
|
* meshesEqual: (a: Mesh, b: Mesh, atol?: number, rtol?: number, unordered?: boolean) => boolean,
|
|
147
|
-
* merge: (meshes: Mesh[], weld?: boolean, atol?: number, sourceTag?: boolean, dataPolicy?: string, dropDuplicateCells?: boolean) => Mesh,
|
|
227
|
+
* merge: (meshes: Mesh[], weld?: boolean, atol?: number, sourceTag?: boolean, dataPolicy?: string, dropDuplicateCells?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMaps: Int32Array[], cellMaps: Int32Array[]},
|
|
148
228
|
* transform: (mesh: Mesh, matrix: number[], rotateVectorData?: boolean) => Mesh,
|
|
149
|
-
* clean: (mesh: Mesh, weld?: boolean, atol?: number, removeOrphans?: boolean, dropDegenerate?: boolean, dropDuplicateCells?: boolean) => {mesh: Mesh, pointsWelded: number, pointsRemovedOrphan: number, cellsDroppedDegenerate: number, cellsDroppedDuplicate: number},
|
|
150
|
-
* smooth: (mesh: Mesh, method?: string, iterations?: number, lambda?: number, mu?: number, fixBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, guardInversion?: boolean) => {mesh: Mesh, numNodesMoved: number, maxDisplacement: number, numSkippedInversion: number},
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
229
|
+
* clean: (mesh: Mesh, weld?: boolean, atol?: number, removeOrphans?: boolean, dropDegenerate?: boolean, dropDuplicateCells?: boolean, returnMaps?: boolean) => {mesh: Mesh, pointsWelded: number, pointsRemovedOrphan: number, cellsDroppedDegenerate: number, cellsDroppedDuplicate: number, pointMap?: Int32Array, cellMaps?: Int32Array[]},
|
|
230
|
+
* smooth: (mesh: Mesh, method?: string, iterations?: number, lambda?: number, mu?: number, fixBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, guardInversion?: boolean, frozen?: number[]|Int32Array|null) => {mesh: Mesh, numNodesMoved: number, maxDisplacement: number, numSkippedInversion: number},
|
|
231
|
+
* interpolate: (source: Mesh, target: Mesh, method?: string, arrays?: string[], extrapolate?: boolean, defaultValue?: number, onConflict?: string) => Mesh,
|
|
232
|
+
* conservativeInterpolate: (source: Mesh, target: Mesh, arrays?: string[], defaultValue?: number, onConflict?: string) => Mesh,
|
|
233
|
+
* undoGreen: (coarse: Mesh, fine: Mesh) => {mesh: Mesh, numGroupsUndone: number, numCellsRemoved: number},
|
|
234
|
+
* cropBbox: (mesh: Mesh, lo: number[], hi: number[], mode?: string, recordIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
235
|
+
* cropPlane: (mesh: Mesh, point: number[], normal: number[], mode?: string, recordIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
236
|
+
* cropPredicate: (mesh: Mesh, array: string, compare?: string, value?: number, recordIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
154
237
|
* slice: (mesh: Mesh, origin: number[], normal: number[], recordParentIds?: boolean) => Mesh,
|
|
155
238
|
* isosurface: (mesh: Mesh, array: string, isovalues: number|number[], component?: number, recordParentIds?: boolean) => Mesh,
|
|
156
239
|
* grid: (dims: number[], origin?: number[], spacing?: number[], maxCells?: number) => Mesh,
|
|
@@ -165,13 +248,20 @@ function resolveVariant(variant) {
|
|
|
165
248
|
* remesh: (mesh: Mesh, numClusters: number, subdivide?: number, subsampleRatio?: number, maxSubdivide?: number, maxIterations?: number, maxRepairPasses?: number, metric?: string, gradation?: number, preserveBoundary?: boolean, maxAnisotropy?: number) => {mesh: Mesh, numClusters: number, numIterations: number, subdivideApplied: number, numIsolatedClusters: number, numNonManifoldVertices: number},
|
|
166
249
|
* remeshVolume: (mesh: Mesh, resolution?: number[], cellSize?: number, bounds?: number[], padding?: number, paddingRelative?: number, maxCells?: number, maxTets?: number, warpFraction?: number, sign?: string, watertightCheck?: string) => {mesh: Mesh, numTets: number, numVerticesWarped: number, numTetsRejected: number, numNonManifoldEdges: number},
|
|
167
250
|
* optimizeVolume: (mesh: Mesh, maxIterations?: number, relocate?: boolean, flip?: boolean, preserveBoundary?: boolean, minImprovement?: number) => {mesh: Mesh, numFlips: number, num23Flips: number, num32Flips: number, numVerticesMoved: number, numTets: number, minQualityBefore: number, minQualityAfter: number},
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
251
|
+
* computeCurvature: (mesh: Mesh, mean?: boolean, gaussian?: boolean, dualArea?: string, includeBoundary?: boolean, recordArea?: boolean, recordPrincipal?: boolean, region?: string) => {mesh: Mesh, numBoundary: number, numIsolated: number, numDegenerate: number, totalAngleDefect: number, quality: {boundaryEdges: number, nonManifoldEdges: number, inconsistentPairs: number, degenerateTriangles: number, watertight: boolean}},
|
|
252
|
+
* repair: (mesh: Mesh, fixOrientation?: boolean, orientOutward?: boolean, fillHoles?: boolean, splitNonManifold?: boolean, maxHoleEdges?: number, weldTolerance?: number, recordProvenance?: boolean) => {mesh: Mesh, qualityBefore: object, qualityAfter: object, numFlipped: number, numComponents: number, largestComponent: number, numOrientedOutward: number, numUnorientable: number, numVerticesSplit: number, numHolesDetected: number, numHolesFilled: number, numHolesSkipped: number, numFacesAdded: number, numPointsAdded: number, pointsWelded: number},
|
|
253
|
+
* shrinkwrap: (mesh: Mesh, target: Mesh, offset?: number, maxDistance?: number, weights?: string, targetRegion?: string, normalWeight?: string, recordDistance?: boolean, recordClosestCell?: boolean) => {mesh: Mesh, quality: object, numProjected: number, numMissed: number, numSkipped: number, maxDisplacement: number},
|
|
254
|
+
* sobolevDeform: (mesh: Mesh, array: string, lengthScale: number, fixedPointsArray?: string, fixBoundary?: boolean, recordFiltered?: boolean, maxIterations?: number, tolerance?: number) => {mesh: Mesh, numIterations: number, residual: number, converged: boolean, numFixed: number, numIsolated: number, maxDisplacement: number},
|
|
255
|
+
* split: (mesh: Mesh, by: string, tagName?: string, returnMaps?: boolean) => {key: string, mesh: Mesh, pointMap?: Int32Array, cellMaps?: Int32Array[]}[],
|
|
256
|
+
* convertCells: (mesh: Mesh, mode?: string, recordParentIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
257
|
+
* subdivide: (mesh: Mesh, recordParentIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, cellMaps: Int32Array[]},
|
|
258
|
+
* agglomerate: (mesh: Mesh, targetGroupSize?: number, returnMaps?: boolean) => Mesh | {mesh: Mesh, cellMap: Int32Array},
|
|
172
259
|
* refine: (mesh: Mesh, levels?: number, recordParentIds?: boolean,
|
|
173
|
-
* options?: object) => Mesh,
|
|
174
|
-
* decimate: (mesh: Mesh, ratio?: number, targetFaces?: number, maxError?: number, placement?: string, preserveBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number) => {mesh: Mesh, facesRemoved: number, pointsRemoved: number, collapsesRejected: number, maxErrorApplied: number},
|
|
260
|
+
* options?: object, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
261
|
+
* decimate: (mesh: Mesh, ratio?: number, targetFaces?: number, maxError?: number, placement?: string, preserveBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, frozen?: number[]|Int32Array|null, returnMaps?: boolean) => {mesh: Mesh, facesRemoved: number, pointsRemoved: number, collapsesRejected: number, maxErrorApplied: number, pointMap?: Int32Array, cellMaps?: Int32Array[]},
|
|
262
|
+
* decimateVolume: (mesh: Mesh, ratio?: number, targetCells?: number, maxError?: number, placement?: string, preserveBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, frozen?: number[]|Int32Array|null, returnMaps?: boolean) => {mesh: Mesh, tetsRemoved: number, pointsRemoved: number, collapsesRejected: number, maxErrorApplied: number, pointMap?: Int32Array, cellMaps?: Int32Array[]},
|
|
263
|
+
* partition: (mesh: Mesh, nparts: number, method?: string, imbalance?: number, mode?: string, seed?: number, recordIds?: boolean, ghostLayers?: number, weightsKey?: string, returnMaps?: boolean) => {partId: number, mesh: Mesh, pointMap?: Int32Array, cellMaps?: Int32Array[]}[],
|
|
264
|
+
* partitionLabels: (mesh: Mesh, nparts: number, method?: string, imbalance?: number, mode?: string, seed?: number, weightsKey?: string) => number[][],
|
|
175
265
|
* stats: (mesh: Mesh) => object,
|
|
176
266
|
* withProvenance: <T>(mode: number|null|undefined, fn: () => T) => T,
|
|
177
267
|
* provenanceBegin: (mode?: number) => void,
|
|
@@ -190,17 +280,75 @@ function resolveVariant(variant) {
|
|
|
190
280
|
* dataInfo: (mesh: Mesh) => object[],
|
|
191
281
|
* dataIntegrate: (mesh: Mesh, arrays?: string[]) => object[],
|
|
192
282
|
* createXdmfTimeSeriesWriter: (path: string, options?: {dataFormat?: string, gzipLevel?: number, mode?: 'truncate'|'append', autoFlush?: boolean}) => XdmfTimeSeriesWriter,
|
|
283
|
+
* openSequence: (source: string|string[], options?: object) => SequenceReader,
|
|
193
284
|
* }>}
|
|
285
|
+
* @throws {MeshioPlusPlusLoadError} if the WASM module fails to instantiate.
|
|
194
286
|
*/
|
|
195
287
|
export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto' } = {}) {
|
|
196
288
|
const chosen = resolveVariant(variant);
|
|
289
|
+
const glue =
|
|
290
|
+
chosen === 'mt' ? '../dist/meshioplusplus_wasm_mt.mjs' : '../dist/meshioplusplus_wasm.mjs';
|
|
197
291
|
// Literal specifiers so bundlers emit both chunks; the sequential one is
|
|
198
292
|
// the fallback whenever threads are unavailable.
|
|
199
293
|
const { default: createRawModule } =
|
|
200
294
|
chosen === 'mt'
|
|
201
295
|
? await import('../dist/meshioplusplus_wasm_mt.mjs')
|
|
202
296
|
: await import('../dist/meshioplusplus_wasm.mjs');
|
|
203
|
-
|
|
297
|
+
|
|
298
|
+
// Wrap locateFile/onAbort (rather than passing moduleOverrides through
|
|
299
|
+
// untouched) so a failed instantiation can be reported with which file
|
|
300
|
+
// Emscripten actually asked for and what locateFile resolved it to,
|
|
301
|
+
// instead of a bare Emscripten abort message. onAbort is overridden even
|
|
302
|
+
// though the try/catch below is the primary path, because an abort under
|
|
303
|
+
// Node does not always surface as a catchable rejection in every
|
|
304
|
+
// Emscripten build -- this guarantees the reason is captured regardless.
|
|
305
|
+
const userLocateFile = moduleOverrides.locateFile;
|
|
306
|
+
const userOnAbort = moduleOverrides.onAbort;
|
|
307
|
+
let requestedFile;
|
|
308
|
+
let resolvedUrl;
|
|
309
|
+
let abortReason;
|
|
310
|
+
const wrappedOverrides = {
|
|
311
|
+
...moduleOverrides,
|
|
312
|
+
locateFile: (path, prefix) => {
|
|
313
|
+
requestedFile = path;
|
|
314
|
+
resolvedUrl = userLocateFile ? userLocateFile(path, prefix) : prefix + path;
|
|
315
|
+
return resolvedUrl;
|
|
316
|
+
},
|
|
317
|
+
onAbort: (reason) => {
|
|
318
|
+
abortReason = reason;
|
|
319
|
+
if (userOnAbort) userOnAbort(reason);
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
let Module;
|
|
324
|
+
try {
|
|
325
|
+
Module = await createRawModule(wrappedOverrides);
|
|
326
|
+
} catch (cause) {
|
|
327
|
+
throw new MeshioPlusPlusLoadError(
|
|
328
|
+
`meshio++ (wasm): failed to instantiate the '${chosen}' variant (${glue}): ` +
|
|
329
|
+
`${abortReason ?? cause.message ?? cause}. Emscripten requested ` +
|
|
330
|
+
`'${requestedFile}' and locateFile returned '${resolvedUrl}'.`,
|
|
331
|
+
{ variant: chosen, glue, requestedFile, resolvedUrl, cause },
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// A mismatched locateFile (e.g. the seq .wasm handed to the mt glue) does
|
|
336
|
+
// not always fail instantiation with a LinkError -- the two binaries share
|
|
337
|
+
// enough of an export surface that it can link and then silently behave
|
|
338
|
+
// like the wrong variant. parallelBackend() is the cheap, always-present
|
|
339
|
+
// tell: catch it here rather than let every caller re-discover it.
|
|
340
|
+
const expectedBackend = chosen === 'mt' ? 'openmp' : 'seq';
|
|
341
|
+
const actualBackend = Module.parallelBackend();
|
|
342
|
+
if (actualBackend !== expectedBackend) {
|
|
343
|
+
throw new MeshioPlusPlusLoadError(
|
|
344
|
+
`meshio++ (wasm): failed to instantiate the '${chosen}' variant (${glue}): ` +
|
|
345
|
+
`loaded, but reports parallel backend '${actualBackend}' (expected ` +
|
|
346
|
+
`'${expectedBackend}') -- locateFile likely returned the wrong .wasm binary. ` +
|
|
347
|
+
`Emscripten requested '${requestedFile}' and locateFile returned '${resolvedUrl}'.`,
|
|
348
|
+
{ variant: chosen, glue, requestedFile, resolvedUrl },
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
204
352
|
return {
|
|
205
353
|
FS: Module.FS,
|
|
206
354
|
readMesh: (path, format = '') => Module.readMesh(path, format),
|
|
@@ -212,6 +360,11 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
212
360
|
// first, negative counts from the end, out of range throws.
|
|
213
361
|
// `lenient` downgrades "this reader cannot represent construct X" to a
|
|
214
362
|
// warning plus a skip; a malformed file still throws.
|
|
363
|
+
// `info: true` attaches the format's side channel as `mesh.info`
|
|
364
|
+
// (openfoam/med/mdpa/ansysinp/unv/gmsh/exodus; ignored, not thrown,
|
|
365
|
+
// for any other format) -- see doc/wasm.md's "Side channel (info)"
|
|
366
|
+
// section. `pointsOnly`/`arrays` reach it only for the formats whose
|
|
367
|
+
// info reader takes selective-read options (med/mdpa/gmsh/exodus).
|
|
215
368
|
readMeshSelective: (
|
|
216
369
|
path,
|
|
217
370
|
{
|
|
@@ -220,15 +373,37 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
220
373
|
arrays = null,
|
|
221
374
|
timeStep = 0,
|
|
222
375
|
lenient = false,
|
|
376
|
+
info = false,
|
|
223
377
|
} = {},
|
|
224
|
-
) => Module.readMeshSelective(path, format, pointsOnly, arrays, timeStep, lenient),
|
|
378
|
+
) => Module.readMeshSelective(path, format, pointsOnly, arrays, timeStep, lenient, info),
|
|
225
379
|
// Summarize a file without loading its heavy arrays. The returned
|
|
226
380
|
// object's `fellBackToFullRead` says whether that was actually cheap.
|
|
227
381
|
readMetadata: (path, format = '') => Module.readMetadata(path, format),
|
|
228
382
|
readerSupportsOptions: (format) => Module.readerSupportsOptions(format),
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
383
|
+
// `options`: `{encoding, codec, floatFormat, info}`, all optional --
|
|
384
|
+
// unset/empty reproduces the exact pre-v11.2.0 write. `encoding` is
|
|
385
|
+
// 'ascii'/'binary' (format-default otherwise); `codec` is a VTK-XML
|
|
386
|
+
// (vtu/vtp) block-compression codec, 'none'/'zlib'/'lz4'/'zstd'; an
|
|
387
|
+
// option a format cannot honour throws naming the format. `info`
|
|
388
|
+
// writes that format's side channel (openfoam/mdpa/ansysinp/unv/gmsh/
|
|
389
|
+
// med); when omitted, `mesh.info` is used instead if its own
|
|
390
|
+
// `format` matches this write's -- a read(info:true) round-trips
|
|
391
|
+
// back through a write with no extra plumbing. `info` given for a
|
|
392
|
+
// format with no side-channel writer (e.g. exodus, read-only, or any
|
|
393
|
+
// format without one at all) throws naming it. Returns every
|
|
394
|
+
// virtual-FS path the write touched (new or changed), sorted -- more
|
|
395
|
+
// than one for a multi-file writer (`.xdmf` + its `.h5` companion,
|
|
396
|
+
// an OpenFOAM `polyMesh` directory's files, ...).
|
|
397
|
+
writeMesh: (path, mesh, format = '', options = undefined) =>
|
|
398
|
+
Module.writeMesh(path, mesh, format, options),
|
|
399
|
+
// `options` adds `encoding`/`codec`/`floatFormat` to `inFormat`/
|
|
400
|
+
// `outFormat` (see `writeMesh`). Returns the written paths, as
|
|
401
|
+
// `writeMesh` does.
|
|
402
|
+
convert: (
|
|
403
|
+
inPath,
|
|
404
|
+
outPath,
|
|
405
|
+
{ inFormat = '', outFormat = '', encoding, codec, floatFormat } = {},
|
|
406
|
+
) => Module.convert(inPath, inFormat, outPath, outFormat, { encoding, codec, floatFormat }),
|
|
232
407
|
// Like `convert`, but writes a renderable *surface*: a volume mesh
|
|
233
408
|
// becomes its boundary, everything else passes through, and the result
|
|
234
409
|
// is linearized. Prefer this over readMesh -> extractSkin -> writeMesh
|
|
@@ -303,6 +478,9 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
303
478
|
Module.diff(a, b, atol, rtol, unordered),
|
|
304
479
|
meshesEqual: (a, b, atol = 0, rtol = 0, unordered = false) =>
|
|
305
480
|
Module.meshesEqual(a, b, atol, rtol, unordered),
|
|
481
|
+
// `returnMaps` (default false): when true, returns
|
|
482
|
+
// `{mesh, pointMaps, cellMaps}` instead of a bare mesh -- one array
|
|
483
|
+
// per input mesh, in input order.
|
|
306
484
|
merge: (
|
|
307
485
|
meshes,
|
|
308
486
|
weld = false,
|
|
@@ -310,9 +488,15 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
310
488
|
sourceTag = true,
|
|
311
489
|
dataPolicy = 'intersection',
|
|
312
490
|
dropDuplicateCells = false,
|
|
313
|
-
|
|
491
|
+
returnMaps = false,
|
|
492
|
+
) =>
|
|
493
|
+
Module.merge(
|
|
494
|
+
meshes, weld, atol, sourceTag, dataPolicy, dropDuplicateCells, returnMaps,
|
|
495
|
+
),
|
|
314
496
|
transform: (mesh, matrix, rotateVectorData = false) =>
|
|
315
497
|
Module.transform(mesh, matrix, rotateVectorData),
|
|
498
|
+
// `returnMaps` (default false): when true, the result also carries
|
|
499
|
+
// `pointMap`/`cellMaps` (input index -> output index, -1 if dropped).
|
|
316
500
|
clean: (
|
|
317
501
|
mesh,
|
|
318
502
|
weld = false,
|
|
@@ -320,10 +504,16 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
320
504
|
removeOrphans = true,
|
|
321
505
|
dropDegenerate = true,
|
|
322
506
|
dropDuplicateCells = true,
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
507
|
+
returnMaps = false,
|
|
508
|
+
) =>
|
|
509
|
+
Module.clean(
|
|
510
|
+
mesh, weld, atol, removeOrphans, dropDegenerate, dropDuplicateCells, returnMaps,
|
|
511
|
+
),
|
|
512
|
+
// `method` is 'taubin', 'laplacian' or 'odt' (tet-only). A negative
|
|
513
|
+
// `lambda` means "this method's own default" (0.5 Laplacian, 0.33
|
|
514
|
+
// Taubin) and is forwarded unchanged. `frozen` is an optional array of
|
|
515
|
+
// 0-based point ids to pin outright, unioned with any boundary/feature
|
|
516
|
+
// pins; an out-of-range id throws by name.
|
|
327
517
|
smooth: (
|
|
328
518
|
mesh,
|
|
329
519
|
method = 'taubin',
|
|
@@ -334,6 +524,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
334
524
|
preserveFeatures = true,
|
|
335
525
|
featureAngle = 30,
|
|
336
526
|
guardInversion = true,
|
|
527
|
+
frozen = null,
|
|
337
528
|
) =>
|
|
338
529
|
Module.smooth(
|
|
339
530
|
mesh,
|
|
@@ -345,6 +536,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
345
536
|
preserveFeatures,
|
|
346
537
|
featureAngle,
|
|
347
538
|
guardInversion,
|
|
539
|
+
frozen,
|
|
348
540
|
),
|
|
349
541
|
// Cross-mesh field transfer: source point_data sampled at the target's
|
|
350
542
|
// points, source cell_data by nearest source-cell centroid regardless
|
|
@@ -387,12 +579,15 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
387
579
|
// Restore `fine`'s transitional (green) cells to their coarse parent,
|
|
388
580
|
// read verbatim from `coarse` (a lookup, not a reconstruction).
|
|
389
581
|
undoGreen: (coarse, fine) => Module.undoGreen(coarse, fine),
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
Module.
|
|
394
|
-
|
|
395
|
-
Module.
|
|
582
|
+
// Each crop* returns a bare mesh, or `{mesh, pointMap, cellMaps}` when
|
|
583
|
+
// `returnMaps` (the trailing argument, default false) is set.
|
|
584
|
+
cropBbox: (mesh, lo, hi, mode = 'all', recordIds = false, returnMaps = false) =>
|
|
585
|
+
Module.cropBbox(mesh, lo, hi, mode, recordIds, returnMaps),
|
|
586
|
+
cropPlane: (mesh, point, normal, mode = 'all', recordIds = false, returnMaps = false) =>
|
|
587
|
+
Module.cropPlane(mesh, point, normal, mode, recordIds, returnMaps),
|
|
588
|
+
cropPredicate: (
|
|
589
|
+
mesh, array, compare = '<', value = 0, recordIds = false, returnMaps = false,
|
|
590
|
+
) => Module.cropPredicate(mesh, array, compare, value, recordIds, returnMaps),
|
|
396
591
|
slice: (mesh, origin, normal, recordParentIds = false) =>
|
|
397
592
|
Module.slice(mesh, origin, normal, recordParentIds),
|
|
398
593
|
grid: (dims, origin = null, spacing = null, maxCells = 20000000) =>
|
|
@@ -545,15 +740,82 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
545
740
|
) =>
|
|
546
741
|
Module.optimizeVolume(mesh, maxIterations, relocate, flip, preserveBoundary,
|
|
547
742
|
minImprovement),
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
743
|
+
computeCurvature: (
|
|
744
|
+
mesh,
|
|
745
|
+
mean = true,
|
|
746
|
+
gaussian = true,
|
|
747
|
+
dualArea = 'mixed-voronoi',
|
|
748
|
+
includeBoundary = false,
|
|
749
|
+
recordArea = false,
|
|
750
|
+
recordPrincipal = false,
|
|
751
|
+
region = '',
|
|
752
|
+
) =>
|
|
753
|
+
Module.computeCurvature(mesh, mean, gaussian, dualArea, includeBoundary,
|
|
754
|
+
recordArea, recordPrincipal, region),
|
|
755
|
+
repair: (
|
|
756
|
+
mesh,
|
|
757
|
+
fixOrientation = true,
|
|
758
|
+
orientOutward = true,
|
|
759
|
+
fillHoles = true,
|
|
760
|
+
splitNonManifold = true,
|
|
761
|
+
maxHoleEdges = 10,
|
|
762
|
+
weldTolerance = 0,
|
|
763
|
+
recordProvenance = false,
|
|
764
|
+
) =>
|
|
765
|
+
Module.repair(mesh, fixOrientation, orientOutward, fillHoles, splitNonManifold,
|
|
766
|
+
maxHoleEdges, weldTolerance, recordProvenance),
|
|
767
|
+
shrinkwrap: (
|
|
768
|
+
mesh,
|
|
769
|
+
target,
|
|
770
|
+
offset = 0,
|
|
771
|
+
maxDistance = 0,
|
|
772
|
+
weights = '',
|
|
773
|
+
targetRegion = '',
|
|
774
|
+
normalWeight = 'angle',
|
|
775
|
+
recordDistance = false,
|
|
776
|
+
recordClosestCell = false,
|
|
777
|
+
) =>
|
|
778
|
+
Module.shrinkwrap(mesh, target, offset, maxDistance, weights, targetRegion,
|
|
779
|
+
normalWeight, recordDistance, recordClosestCell),
|
|
780
|
+
sobolevDeform: (
|
|
781
|
+
mesh,
|
|
782
|
+
array,
|
|
783
|
+
lengthScale,
|
|
784
|
+
fixedPointsArray = '',
|
|
785
|
+
fixBoundary = false,
|
|
786
|
+
recordFiltered = false,
|
|
787
|
+
maxIterations = 128,
|
|
788
|
+
tolerance = 1e-10,
|
|
789
|
+
) =>
|
|
790
|
+
Module.sobolevDeform(mesh, array, lengthScale, fixedPointsArray, fixBoundary,
|
|
791
|
+
recordFiltered, maxIterations, tolerance),
|
|
792
|
+
// `returnMaps` (default false): when true, each `{key, mesh}` piece
|
|
793
|
+
// also carries `pointMap`/`cellMaps`.
|
|
794
|
+
split: (mesh, by, tagName = '', returnMaps = false) =>
|
|
795
|
+
Module.split(mesh, by, tagName, returnMaps),
|
|
796
|
+
// `returnMaps` (default false): when true, returns
|
|
797
|
+
// `{mesh, pointMap, cellMaps}` instead of a bare mesh.
|
|
798
|
+
convertCells: (mesh, mode = 'linearize', recordParentIds = false, returnMaps = false) =>
|
|
799
|
+
Module.convertCells(mesh, mode, recordParentIds, returnMaps),
|
|
800
|
+
// `returnMaps` (default false): when true, returns `{mesh, cellMaps}`
|
|
801
|
+
// instead of a bare mesh -- there is no point map (subdivide never
|
|
802
|
+
// prunes or renumbers a point).
|
|
803
|
+
subdivide: (mesh, recordParentIds = false, returnMaps = false) =>
|
|
804
|
+
Module.subdivide(mesh, recordParentIds, returnMaps),
|
|
805
|
+
// `returnMaps` (default false): when true, returns `{mesh, cellMap}`
|
|
806
|
+
// instead of a bare mesh -- a single FLAT array (global cell index ->
|
|
807
|
+
// global cell index), unlike the other ops' per-block `cellMaps`.
|
|
808
|
+
agglomerate: (mesh, targetGroupSize = 8, returnMaps = false) =>
|
|
809
|
+
Module.agglomerate(mesh, targetGroupSize, returnMaps),
|
|
810
|
+
// `returnMaps` (default false): when true, returns
|
|
811
|
+
// `{mesh, pointMap, cellMaps}` instead of a bare mesh.
|
|
812
|
+
refine: (mesh, levels = 1, recordParentIds = false, options = undefined,
|
|
813
|
+
returnMaps = false) =>
|
|
814
|
+
Module.refine(mesh, levels, recordParentIds, options, returnMaps),
|
|
815
|
+
// Exactly one of ratio / targetFaces / maxError must be non-negative.
|
|
816
|
+
// `frozen` is an optional array of 0-based point ids to pin outright;
|
|
817
|
+
// an out-of-range id throws by name. `returnMaps` (default false):
|
|
818
|
+
// when true, the result also carries `pointMap`/`cellMaps`.
|
|
557
819
|
decimate: (
|
|
558
820
|
mesh,
|
|
559
821
|
ratio = -1,
|
|
@@ -563,6 +825,8 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
563
825
|
preserveBoundary = true,
|
|
564
826
|
preserveFeatures = true,
|
|
565
827
|
featureAngle = 30,
|
|
828
|
+
frozen = null,
|
|
829
|
+
returnMaps = false,
|
|
566
830
|
) =>
|
|
567
831
|
Module.decimate(
|
|
568
832
|
mesh,
|
|
@@ -573,7 +837,42 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
573
837
|
preserveBoundary,
|
|
574
838
|
preserveFeatures,
|
|
575
839
|
featureAngle,
|
|
840
|
+
frozen,
|
|
841
|
+
returnMaps,
|
|
576
842
|
),
|
|
843
|
+
// Tetrahedral VOLUME decimation (decimate's tet-edge-collapse sibling).
|
|
844
|
+
// Exactly one of ratio / targetCells / maxError must be non-negative.
|
|
845
|
+
// `preserveBoundary` defaults to false here, matching the C++ default
|
|
846
|
+
// (decimate's own default is true) -- decimateVolume's boundary is
|
|
847
|
+
// usually interior geometry a solver still wants simplified.
|
|
848
|
+
// `returnMaps` (default false): when true, the result also carries
|
|
849
|
+
// `pointMap`/`cellMaps`.
|
|
850
|
+
decimateVolume: (
|
|
851
|
+
mesh,
|
|
852
|
+
ratio = -1,
|
|
853
|
+
targetCells = -1,
|
|
854
|
+
maxError = -1,
|
|
855
|
+
placement = 'optimal',
|
|
856
|
+
preserveBoundary = false,
|
|
857
|
+
preserveFeatures = true,
|
|
858
|
+
featureAngle = 30,
|
|
859
|
+
frozen = null,
|
|
860
|
+
returnMaps = false,
|
|
861
|
+
) =>
|
|
862
|
+
Module.decimateVolume(
|
|
863
|
+
mesh,
|
|
864
|
+
ratio,
|
|
865
|
+
targetCells,
|
|
866
|
+
maxError,
|
|
867
|
+
placement,
|
|
868
|
+
preserveBoundary,
|
|
869
|
+
preserveFeatures,
|
|
870
|
+
featureAngle,
|
|
871
|
+
frozen,
|
|
872
|
+
returnMaps,
|
|
873
|
+
),
|
|
874
|
+
// `returnMaps` (default false): when true, each `{partId, mesh}`
|
|
875
|
+
// piece also carries `pointMap`/`cellMaps`.
|
|
577
876
|
partition: (
|
|
578
877
|
mesh,
|
|
579
878
|
nparts,
|
|
@@ -584,6 +883,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
584
883
|
recordIds = false,
|
|
585
884
|
ghostLayers = 0,
|
|
586
885
|
weightsKey = '',
|
|
886
|
+
returnMaps = false,
|
|
587
887
|
) =>
|
|
588
888
|
Module.partition(
|
|
589
889
|
mesh,
|
|
@@ -595,6 +895,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
595
895
|
recordIds,
|
|
596
896
|
ghostLayers,
|
|
597
897
|
weightsKey,
|
|
898
|
+
returnMaps,
|
|
598
899
|
),
|
|
599
900
|
partitionLabels: (
|
|
600
901
|
mesh,
|
|
@@ -680,7 +981,13 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
680
981
|
// Raw solver arrays instead of a mesh; `components` gives the
|
|
681
982
|
// per-entity width of any array that is not a scalar.
|
|
682
983
|
writeDataArrays: (time, pointData, cellData = {}, components = {}) =>
|
|
683
|
-
Module.xdmfSeriesWriteDataArrays(
|
|
984
|
+
Module.xdmfSeriesWriteDataArrays(
|
|
985
|
+
handle,
|
|
986
|
+
time,
|
|
987
|
+
widenBigIntArrays(pointData),
|
|
988
|
+
widenBigIntArrays(cellData),
|
|
989
|
+
components,
|
|
990
|
+
),
|
|
684
991
|
// Make the `.xdmf` readable now, without finalizing.
|
|
685
992
|
flush: () => Module.xdmfSeriesFlush(handle),
|
|
686
993
|
finalize: () => Module.xdmfSeriesFinalize(handle),
|
|
@@ -700,6 +1007,42 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
700
1007
|
},
|
|
701
1008
|
};
|
|
702
1009
|
},
|
|
1010
|
+
// Stateful sequence reader (see doc/sequences.md) -- the other
|
|
1011
|
+
// stateful thing in this API, the same opaque-handle-plus-free-
|
|
1012
|
+
// functions shape as createXdmfTimeSeriesWriter above. `source`/
|
|
1013
|
+
// `options` are exactly sequenceEntries'; this plans the sequence
|
|
1014
|
+
// once (`entries()`) and lets a caller read one step at a time
|
|
1015
|
+
// (`read()`) without holding more than one mesh alive, unlike
|
|
1016
|
+
// sequenceEntries + readMesh in a loop, which still requires the
|
|
1017
|
+
// caller to resolve the format/step itself.
|
|
1018
|
+
openSequence: (source, options = undefined) => {
|
|
1019
|
+
const handle = Module.sequenceOpen(source, options);
|
|
1020
|
+
const count = Module.sequenceCount(handle);
|
|
1021
|
+
const entry = (i) => ({
|
|
1022
|
+
path: Module.sequencePath(handle, i),
|
|
1023
|
+
step: Module.sequenceStep(handle, i),
|
|
1024
|
+
time: Module.sequenceTime(handle, i),
|
|
1025
|
+
timeSource: Module.sequenceTimeSource(handle, i),
|
|
1026
|
+
});
|
|
1027
|
+
let open = true;
|
|
1028
|
+
return {
|
|
1029
|
+
count,
|
|
1030
|
+
path: (i) => Module.sequencePath(handle, i),
|
|
1031
|
+
step: (i) => Module.sequenceStep(handle, i),
|
|
1032
|
+
time: (i) => Module.sequenceTime(handle, i),
|
|
1033
|
+
timeSource: (i) => Module.sequenceTimeSource(handle, i),
|
|
1034
|
+
entry,
|
|
1035
|
+
entries: () => Array.from({ length: count }, (_, i) => entry(i)),
|
|
1036
|
+
read: (i, { pointsOnly = false, arrays = null, lenient = false } = {}) =>
|
|
1037
|
+
Module.sequenceRead(handle, i, { pointsOnly, arrays, lenient }),
|
|
1038
|
+
// Safe to call twice; safe to call in a `finally`.
|
|
1039
|
+
close: () => {
|
|
1040
|
+
if (!open) return;
|
|
1041
|
+
open = false;
|
|
1042
|
+
Module.sequenceFree(handle);
|
|
1043
|
+
},
|
|
1044
|
+
};
|
|
1045
|
+
},
|
|
703
1046
|
};
|
|
704
1047
|
}
|
|
705
1048
|
|