@meshioplusplus/wasm 16.22.0 → 16.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.
package/index.d.ts CHANGED
@@ -20,6 +20,40 @@ export interface SurfaceQualityInfo {
20
20
  watertight: boolean;
21
21
  }
22
22
 
23
+ /** Names one region: its name plus, optionally, its kind, dimension and tag. */
24
+ export interface RegionSelector {
25
+ name: string;
26
+ kind?: 'point' | 'cell' | 'side';
27
+ dim?: number;
28
+ tag?: number;
29
+ }
30
+
31
+ /** One `editRegions` edit. */
32
+ export interface RegionEdit {
33
+ op: 'union' | 'intersection' | 'difference' | 'rename' | 'retag' | 'delete';
34
+ inputs: Array<string | RegionSelector>;
35
+ output?: string;
36
+ dim?: number;
37
+ tag?: number;
38
+ keepInputs?: boolean;
39
+ }
40
+
41
+ /** `agglomerate`'s options (see doc/agglomerate.md). */
42
+ export interface AgglomerateOptions {
43
+ mergeCoplanarFaces?: boolean;
44
+ coplanarAngle?: number;
45
+ minSphericity?: number;
46
+ }
47
+
48
+ /** `resampleSequence`'s options: the settings document's `Resample` object. */
49
+ export interface ResampleOptions {
50
+ Times?: number[] | { Start: number; Stop: number; Step: number };
51
+ TimesFrom?: string;
52
+ Method?: 'linear' | 'nearest' | 'previous';
53
+ Extrapolate?: 'error' | 'clamp';
54
+ BlendPoints?: boolean;
55
+ }
56
+
23
57
  /**
24
58
  * A `point_data`/`cell_data`/`field_data` array's JS type: it carries its
25
59
  * source dtype crossing the WASM boundary instead of always widening to
@@ -205,13 +239,36 @@ export interface MedInfo {
205
239
  fieldTimeValues: Record<string, number[]>;
206
240
  }
207
241
 
208
- /** MDPA's side channel: per-block entity names. Properties ride on `mesh.propertySets` instead (see {@link PropertySet}), not here. */
242
+ /**
243
+ * MDPA's side channel: per-block entity names and every block the mesh cannot
244
+ * hold. Properties ride on `mesh.propertySets` instead (see {@link PropertySet}),
245
+ * not here. Point references (`geometries[].conn`, `meshBlocks[].nodes`) are
246
+ * 0-based point rows; entity and table ids are the file's own.
247
+ */
209
248
  export interface MdpaInfo {
210
249
  format: 'mdpa';
211
250
  /** One entry per cell block, mesh block order. */
212
251
  entityNames: Array<{ name: string; isCondition: boolean }>;
213
252
  /** Lenient-mode only: constructs this read could not represent, verbatim. */
214
253
  skippedConstructs: string[];
254
+ /** The non-numeric `ModelPartData` entries (`text` set); numeric ones are `fieldData`. */
255
+ modelPartData?: PropertyValue[];
256
+ /** Top-level `Begin Table` blocks: `key` holds the header arguments (`"1 TIME VALUE"`). */
257
+ tables?: PropertyValue[];
258
+ /** `Begin Geometries` runs: `conn` is flat row-major `(n, nodes per geometry)`. */
259
+ geometries?: Array<{ name: string; type: string; conn: Float64Array; ids: number[] }>;
260
+ /** `Begin Mesh <id>` blocks. */
261
+ meshBlocks?: Array<{
262
+ id: number;
263
+ data: PropertyValue[];
264
+ nodes: number[];
265
+ elementIds: number[];
266
+ conditionIds: number[];
267
+ }>;
268
+ /** `SubModelPartData`/`SubModelPartTables` content, by hierarchical part name. */
269
+ subModelParts?: Array<{ name: string; data: PropertyValue[]; tables: number[] }>;
270
+ /** Every other top-level block (`Constraints`, ...), kept verbatim. */
271
+ rawBlocks?: Array<{ header: string; body: string; end: string }>;
215
272
  }
216
273
 
217
274
  /**
@@ -1192,6 +1249,34 @@ export interface MeshioPlusPlusModule {
1192
1249
  *
1193
1250
  * @returns the number of steps written.
1194
1251
  */
1252
+ /**
1253
+ * Resample `source` onto new times and write it to `outPath`: one file per
1254
+ * target time when it carries `{step}`/`{index}`, else one series file.
1255
+ * `resample` is the settings document's `Resample` object. At most two
1256
+ * source meshes are alive at once. See doc/sequences.md.
1257
+ *
1258
+ * @returns the number of target times written.
1259
+ */
1260
+ resampleSequence(
1261
+ source: string | string[],
1262
+ outPath: string,
1263
+ resample: ResampleOptions,
1264
+ outFormat?: string,
1265
+ options?: {
1266
+ format?: string;
1267
+ times?: number[];
1268
+ timeFrom?: 'auto' | 'file' | 'filename' | 'index';
1269
+ sort?: boolean;
1270
+ },
1271
+ ): number;
1272
+
1273
+ /**
1274
+ * `a` with every floating-point data array replaced by `(1 - w) a + w b`
1275
+ * (integer data from the nearer step); both steps must share a topology.
1276
+ * `blendPoints` blends the coordinates too.
1277
+ */
1278
+ blendSteps(a: Mesh, b: Mesh, w: number, blendPoints?: boolean): Mesh;
1279
+
1195
1280
  sequenceToTimeseries(
1196
1281
  source: string | string[],
1197
1282
  outPath: string,
@@ -1942,6 +2027,125 @@ export interface MeshioPlusPlusModule {
1942
2027
  quality: SurfaceQualityInfo;
1943
2028
  };
1944
2029
 
2030
+ /**
2031
+ * Quality gate: score every cell and test the `require` thresholds (text
2032
+ * such as `'scaled_jacobian >= 0.2; aspect_ratio <= 5 @ 1%'`) plus the
2033
+ * inverted and degenerate cell counts (`maxInverted`/`maxDegenerate`,
2034
+ * default 0, negative disables). `summary` is the text both CLIs print. See
2035
+ * doc/mesh_quality.md.
2036
+ * @throws {Error} on a malformed specification or an unknown metric.
2037
+ */
2038
+ checkQuality(
2039
+ mesh: Mesh,
2040
+ require?: string,
2041
+ maxInverted?: number,
2042
+ maxDegenerate?: number,
2043
+ ): {
2044
+ passed: boolean;
2045
+ numCells: number;
2046
+ numInverted: number;
2047
+ numDegenerate: number;
2048
+ checks: Array<{
2049
+ name: string;
2050
+ metric: string;
2051
+ min: number;
2052
+ max: number;
2053
+ maxFraction: number;
2054
+ evaluated: number;
2055
+ violations: number;
2056
+ fraction: number;
2057
+ worst: number;
2058
+ worstCell: number;
2059
+ passed: boolean;
2060
+ }>;
2061
+ summary: string;
2062
+ };
2063
+
2064
+ /**
2065
+ * The sharp, open, non-manifold and inconsistently wound edges of a surface
2066
+ * (or of a volume mesh's skin) as a mesh of `line` cells over the input's
2067
+ * points, with cell data `feature:kind` (1 feature, 2 boundary,
2068
+ * 3 non-manifold, 4 inconsistent) and `feature:angle` (degrees). The counts
2069
+ * cover the whole surface, selected or not. See doc/feature_edges.md.
2070
+ * @throws {Error} on an angle outside [0, 180] or an unknown region.
2071
+ */
2072
+ featureEdges(
2073
+ mesh: Mesh,
2074
+ featureAngle?: number,
2075
+ feature?: boolean,
2076
+ boundary?: boolean,
2077
+ nonManifold?: boolean,
2078
+ inconsistent?: boolean,
2079
+ region?: string,
2080
+ ): {
2081
+ mesh: Mesh;
2082
+ numFeature: number;
2083
+ numBoundary: number;
2084
+ numNonManifold: number;
2085
+ numInconsistent: number;
2086
+ };
2087
+
2088
+ /**
2089
+ * The (sampled) Hausdorff distance between the surfaces of two meshes; a
2090
+ * volume mesh contributes its skin. `faceSamples = s > 0` also samples the
2091
+ * centroids of the `s*s` sub-triangles of every triangle (vertices alone
2092
+ * give a lower bound). See doc/hausdorff.md.
2093
+ * @throws {Error} when a mesh has no surface triangles.
2094
+ */
2095
+ hausdorffDistance(
2096
+ a: Mesh,
2097
+ b: Mesh,
2098
+ faceSamples?: number,
2099
+ regionA?: string,
2100
+ regionB?: string,
2101
+ ): {
2102
+ distance: number;
2103
+ aToB: number;
2104
+ bToA: number;
2105
+ meanAToB: number;
2106
+ rmsAToB: number;
2107
+ meanBToA: number;
2108
+ rmsBToA: number;
2109
+ numSamplesA: number;
2110
+ numSamplesB: number;
2111
+ worstPointA: Float64Array;
2112
+ worstPointB: Float64Array;
2113
+ };
2114
+
2115
+ /**
2116
+ * Apply region edits, in order, to a copy of `mesh` (points, cells and data
2117
+ * untouched): `union`, `intersection`, `difference` (two or more inputs of
2118
+ * one kind, result named `output`), `rename`, `retag` (`tag`/`dim`) and
2119
+ * `delete`. An input names exactly one region; pin `kind`/`dim`/`tag` when a
2120
+ * name is shared. See doc/regions.md.
2121
+ * @throws {Error} on a missing or ambiguous region, mixed kinds, or a result
2122
+ * that would replace an unrelated region.
2123
+ */
2124
+ editRegions(mesh: Mesh, edits: RegionEdit | RegionEdit[]): Mesh;
2125
+
2126
+ /**
2127
+ * The master node each node of the `slave` region maps onto under the
2128
+ * row-major 4x4 affine `matrix` (16 numbers), within `atol`. `slave` is
2129
+ * ascending and `master` aligned with it (0-based point ids). See
2130
+ * doc/periodic.md.
2131
+ * @throws {Error} on a master claimed twice or, with `requireComplete`, an
2132
+ * unmatched slave node.
2133
+ */
2134
+ matchPeriodicNodes(
2135
+ mesh: Mesh,
2136
+ slave: string | RegionSelector,
2137
+ master: string | RegionSelector,
2138
+ matrix: ArrayLike<number>,
2139
+ atol?: number,
2140
+ requireComplete?: boolean,
2141
+ ): {
2142
+ slave: Int32Array;
2143
+ master: Int32Array;
2144
+ unmatched: Int32Array;
2145
+ numFixed: number;
2146
+ maxResidual: number;
2147
+ };
2148
+
1945
2149
  /**
1946
2150
  * Surface repair beyond `clean`: weld (opt-in) -> triangulate -> split
1947
2151
  * bowties -> orient by the topological half-edge rule per connected
@@ -2090,10 +2294,26 @@ export interface MeshioPlusPlusModule {
2090
2294
  *
2091
2295
  * With `returnMaps: true`, returns `{mesh, cellMap}` instead of a bare
2092
2296
  * mesh -- a single FLAT array (global input cell index -> global output
2093
- * cell index), unlike the other ops' per-block `cellMaps`.
2297
+ * cell index), unlike the other ops' per-block `cellMaps` -- plus
2298
+ * `numFacesMerged` and `numRejected` for the `options` below.
2299
+ *
2300
+ * `options.mergeCoplanarFaces` fuses coplanar shared and boundary faces
2301
+ * (within `coplanarAngle` degrees, default 1) into one polygon;
2302
+ * `options.minSphericity` (0 = off) refuses an absorption that would drop a
2303
+ * group's sphericity below it. See doc/agglomerate.md.
2094
2304
  */
2095
- agglomerate(mesh: Mesh, targetGroupSize?: number, returnMaps?: false): Mesh;
2096
- agglomerate(mesh: Mesh, targetGroupSize?: number, returnMaps?: true): { mesh: Mesh; cellMap: Int32Array };
2305
+ agglomerate(
2306
+ mesh: Mesh,
2307
+ targetGroupSize?: number,
2308
+ returnMaps?: false,
2309
+ options?: AgglomerateOptions,
2310
+ ): Mesh;
2311
+ agglomerate(
2312
+ mesh: Mesh,
2313
+ targetGroupSize: number | undefined,
2314
+ returnMaps: true,
2315
+ options?: AgglomerateOptions,
2316
+ ): { mesh: Mesh; cellMap: Int32Array; numFacesMerged: number; numRejected: number };
2097
2317
 
2098
2318
  /**
2099
2319
  * Refine a mesh, subdividing cells into same-type children (`line` → 2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshioplusplus/wasm",
3
- "version": "16.22.0",
3
+ "version": "16.27.0",
4
4
  "description": "meshio++ mesh I/O compiled to WebAssembly: read 76 and write 68 mesh formats (incl. MED, CGNS, Exodus) in the browser or Node.js",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
package/src/index.mjs CHANGED
@@ -210,6 +210,8 @@ export class MeshioPlusPlusLoadError extends Error {
210
210
  * sequenceEntries: (source: string|string[], options?: object) => object[],
211
211
  * sequenceToTimeseries: (source: string|string[], outPath: string, outFormat?: string, options?: object) => number,
212
212
  * timeseriesToSequence: (inPath: string, outPattern: string, inFormat?: string, outFormat?: string) => string[],
213
+ * resampleSequence: (source: string|string[], outPath: string, resample: object, outFormat?: string, options?: object) => number,
214
+ * blendSteps: (a: Mesh, b: Mesh, w: number, blendPoints?: boolean) => Mesh,
213
215
  * numNodesPerCell: () => Object<string, number>,
214
216
  * topologicalDimension: () => Object<string, number>,
215
217
  * meshBackend: () => string,
@@ -250,13 +252,18 @@ export class MeshioPlusPlusLoadError extends Error {
250
252
  * 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},
251
253
  * 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
254
  * computeNormals: (mesh: Mesh, pointNormals?: boolean, cellNormals?: boolean, weight?: string, splitAngle?: number, recordParentIds?: boolean, region?: string) => {mesh: Mesh, numIsolated: number, numUndefined: number, numDegenerate: number, numSplitPoints: number, numAddedPoints: number, quality: {boundaryEdges: number, nonManifoldEdges: number, inconsistentPairs: number, degenerateTriangles: number, watertight: boolean}},
255
+ * checkQuality: (mesh: Mesh, require?: string, maxInverted?: number, maxDegenerate?: number) => {passed: boolean, numCells: number, numInverted: number, numDegenerate: number, checks: Array<object>, summary: string},
256
+ * featureEdges: (mesh: Mesh, featureAngle?: number, feature?: boolean, boundary?: boolean, nonManifold?: boolean, inconsistent?: boolean, region?: string) => {mesh: Mesh, numFeature: number, numBoundary: number, numNonManifold: number, numInconsistent: number},
257
+ * hausdorffDistance: (a: Mesh, b: Mesh, faceSamples?: number, regionA?: string, regionB?: string) => {distance: number, aToB: number, bToA: number, meanAToB: number, rmsAToB: number, meanBToA: number, rmsBToA: number, numSamplesA: number, numSamplesB: number, worstPointA: Float64Array, worstPointB: Float64Array},
258
+ * editRegions: (mesh: Mesh, edits: Array<{op: string, inputs: Array<string | {name: string, kind?: string, dim?: number, tag?: number}>, output?: string, dim?: number, tag?: number, keepInputs?: boolean}>) => Mesh,
259
+ * matchPeriodicNodes: (mesh: Mesh, slave: string | {name: string, kind?: string, dim?: number, tag?: number}, master: string | {name: string, kind?: string, dim?: number, tag?: number}, matrix: ArrayLike<number>, atol?: number, requireComplete?: boolean) => {slave: Int32Array, master: Int32Array, unmatched: Int32Array, numFixed: number, maxResidual: number},
253
260
  * 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},
254
261
  * 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},
255
262
  * 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},
256
263
  * split: (mesh: Mesh, by: string, tagName?: string, returnMaps?: boolean) => {key: string, mesh: Mesh, pointMap?: Int32Array, cellMaps?: Int32Array[]}[],
257
264
  * convertCells: (mesh: Mesh, mode?: string, recordParentIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
258
265
  * subdivide: (mesh: Mesh, recordParentIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, cellMaps: Int32Array[]},
259
- * agglomerate: (mesh: Mesh, targetGroupSize?: number, returnMaps?: boolean) => Mesh | {mesh: Mesh, cellMap: Int32Array},
266
+ * agglomerate: (mesh: Mesh, targetGroupSize?: number, returnMaps?: boolean, options?: {mergeCoplanarFaces?: boolean, coplanarAngle?: number, minSphericity?: number}) => Mesh | {mesh: Mesh, cellMap: Int32Array, numFacesMerged: number, numRejected: number},
260
267
  * refine: (mesh: Mesh, levels?: number, recordParentIds?: boolean,
261
268
  * options?: object, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
262
269
  * 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[]},
@@ -460,6 +467,12 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
460
467
  // Streams -- one mesh alive at a time, whatever the step count.
461
468
  sequenceToTimeseries: (source, outPath, outFormat = '', options = undefined) =>
462
469
  Module.sequenceToTimeseries(source, outPath, outFormat, options),
470
+ // Resample onto new times: `resample` is {Times | TimesFrom, Method,
471
+ // Extrapolate, BlendPoints}. At most two meshes alive at a time.
472
+ resampleSequence: (source, outPath, resample, outFormat = '', options = undefined) =>
473
+ Module.resampleSequence(source, outPath, resample, outFormat, options),
474
+ // `a` with its float data blended to (1 - w) a + w b; same topology.
475
+ blendSteps: (a, b, w, blendPoints = false) => Module.blendSteps(a, b, w, blendPoints),
463
476
  // Fan-out: one multi-step file -> one file per step. `outPattern` must
464
477
  // contain '{step}' or '{index}'; returns the MEMFS paths written.
465
478
  timeseriesToSequence: (inPath, outPattern, inFormat = '', outFormat = '') =>
@@ -775,6 +788,26 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
775
788
  ) =>
776
789
  Module.computeNormals(mesh, pointNormals, cellNormals, weight, splitAngle,
777
790
  recordParentIds, region),
791
+ checkQuality: (mesh, require = '', maxInverted = 0, maxDegenerate = 0) =>
792
+ Module.checkQuality(mesh, require, maxInverted, maxDegenerate),
793
+ featureEdges: (
794
+ mesh,
795
+ featureAngle = 30,
796
+ feature = true,
797
+ boundary = true,
798
+ nonManifold = true,
799
+ inconsistent = true,
800
+ region = '',
801
+ ) =>
802
+ Module.featureEdges(mesh, featureAngle, feature, boundary, nonManifold,
803
+ inconsistent, region),
804
+ hausdorffDistance: (a, b, faceSamples = 0, regionA = '', regionB = '') =>
805
+ Module.hausdorffDistance(a, b, faceSamples, regionA, regionB),
806
+ editRegions: (mesh, edits) =>
807
+ Module.editRegions(mesh, Array.isArray(edits) ? edits : [edits]),
808
+ matchPeriodicNodes: (mesh, slave, master, matrix, atol = 1e-8, requireComplete = true) =>
809
+ Module.matchPeriodicNodes(mesh, slave, master, Array.from(matrix), atol,
810
+ requireComplete),
778
811
  repair: (
779
812
  mesh,
780
813
  fixOrientation = true,
@@ -828,8 +861,9 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
828
861
  // `returnMaps` (default false): when true, returns `{mesh, cellMap}`
829
862
  // instead of a bare mesh -- a single FLAT array (global cell index ->
830
863
  // global cell index), unlike the other ops' per-block `cellMaps`.
831
- agglomerate: (mesh, targetGroupSize = 8, returnMaps = false) =>
832
- Module.agglomerate(mesh, targetGroupSize, returnMaps),
864
+ // `options`: {mergeCoplanarFaces, coplanarAngle, minSphericity}.
865
+ agglomerate: (mesh, targetGroupSize = 8, returnMaps = false, options = undefined) =>
866
+ Module.agglomerate(mesh, targetGroupSize, returnMaps, options),
833
867
  // `returnMaps` (default false): when true, returns
834
868
  // `{mesh, pointMap, cellMaps}` instead of a bare mesh.
835
869
  refine: (mesh, levels = 1, recordParentIds = false, options = undefined,