/ concept-collection / mesh-converter
Sign in
concept-collection / mesh-converter
mesh-converter / src / mesh / formats.ts
204 lines · 6.3 KBBlameHistoryRaw
1import type { MeshData, MeshCapabilities } from './types'
3/**
4 * A real mesh format handled by meshio (id = meshio's file_format name).
5 * `capabilities` declares which optional attributes this app preserves when
6 * writing the format — it drives the loss warnings in the UI and which
7 * point-data arrays the bridge attaches on export.
8 */
9export interface MeshFormat {
10 id: string
11 label: string
12 /** File extension including the dot, e.g. ".ply" */
13 extension: string
14 blurb: string
15 capabilities: MeshCapabilities
16 /**
17 * Prebuilt Pyodide packages this format needs (e.g. h5py). Loaded lazily on
18 * first use so the default footprint stays small.
19 */
20 pyodidePackages?: string[]
23export const formats: MeshFormat[] = [
24 {
25 id: 'ply',
26 label: 'PLY (Polygon File Format)',
27 extension: '.ply',
28 blurb:
29 'The Stanford scanner format, widely understood by mesh tools. Stores vertex ' +
30 'normals (nx/ny/nz) and colors (red/green/blue) as standard vertex properties.',
31 capabilities: { normals: true, colors: true },
32 },
33 {
34 id: 'obj',
35 label: 'Wavefront OBJ',
36 extension: '.obj',
37 blurb:
38 'Ubiquitous text format from the graphics world. Carries vertex normals (vn lines) ' +
39 'but has no standard slot for per-vertex colors.',
40 capabilities: { normals: true, colors: false },
41 },
42 {
43 id: 'stl',
44 label: 'STL',
45 extension: '.stl',
46 blurb:
47 'The 3D-printing staple: a bare triangle soup (written binary). Per-facet normals ' +
48 'are kept when present (else recomputed); vertex normals and colors cannot be stored.',
49 capabilities: { normals: false, colors: false },
50 },
51 {
52 id: 'off',
53 label: 'OFF (Object File Format)',
54 extension: '.off',
55 blurb:
56 'Minimal academic text format: vertex coordinates and triangle faces, nothing else ' +
57 '(quad/color OFF variants are not supported by meshio).',
58 capabilities: { normals: false, colors: false },
59 },
60 {
61 id: 'vtk',
62 label: 'VTK legacy',
63 extension: '.vtk',
64 blurb:
65 'Legacy VTK unstructured grid. Normals and colors travel as named point-data ' +
66 'arrays (Normals, RGB), visible in ParaView.',
67 capabilities: { normals: true, colors: true },
68 },
69 {
70 id: 'vtu',
71 label: 'VTU (VTK XML)',
72 extension: '.vtu',
73 blurb:
74 'Modern XML VTK unstructured grid with compressed binary data. Normals and colors ' +
75 'travel as point-data arrays.',
76 capabilities: { normals: true, colors: true },
77 },
78 {
79 id: 'gmsh',
80 label: 'Gmsh MSH',
81 extension: '.msh',
82 blurb:
83 'Native format of the Gmsh mesh generator (v4.1 binary). Normals and colors travel ' +
84 'as NodeData point-data arrays.',
85 capabilities: { normals: true, colors: true },
86 },
87 {
88 id: 'xdmf',
89 label: 'XDMF',
90 extension: '.xdmf',
91 blurb:
92 'XML metadata with HDF5-backed heavy data, common in HPC simulation. Normals and ' +
93 'colors travel as point-data arrays. Loads the h5py package on first use.',
94 capabilities: { normals: true, colors: true },
95 pyodidePackages: ['h5py'],
96 },
97 {
98 id: 'med',
99 label: 'MED (Salome)',
100 extension: '.med',
101 blurb:
102 'HDF5-based format of the Salome platform and code_aster. Normals and colors ' +
103 'travel as point-data fields. Loads the h5py package on first use.',
104 capabilities: { normals: true, colors: true },
105 pyodidePackages: ['h5py'],
106 },
107 {
108 id: 'h5m',
109 label: 'H5M (MOAB)',
110 extension: '.h5m',
111 blurb:
112 'HDF5-based format of the MOAB mesh library. Normals and colors travel as tags. ' +
113 'Loads the h5py package on first use.',
114 capabilities: { normals: true, colors: true },
115 pyodidePackages: ['h5py'],
116 },
117 {
118 id: 'avsucd',
119 label: 'AVS-UCD',
120 extension: '.avs',
121 blurb:
122 'AVS unstructured cell data, a classic visualization text format. Normals and ' +
123 'colors travel as node data.',
124 capabilities: { normals: true, colors: true },
125 },
126 {
127 id: 'abaqus',
128 label: 'Abaqus',
129 extension: '.inp',
130 blurb: 'Abaqus FEA input deck (text). Geometry only.',
131 capabilities: { normals: false, colors: false },
132 },
133 {
134 id: 'nastran',
135 label: 'Nastran',
136 extension: '.bdf',
137 blurb: 'Nastran bulk data file, widespread in structural analysis. Geometry only.',
138 capabilities: { normals: false, colors: false },
139 },
140 {
141 id: 'medit',
142 label: 'Medit',
143 extension: '.mesh',
144 blurb: 'Text format of the Medit/INRIA meshing tools (also used by mmg). Geometry only.',
145 capabilities: { normals: false, colors: false },
146 },
147 {
148 id: 'netgen',
149 label: 'Netgen',
150 extension: '.vol',
151 blurb: 'Native format of the Netgen mesh generator. Geometry only.',
152 capabilities: { normals: false, colors: false },
153 },
154 {
155 id: 'mdpa',
156 label: 'MDPA (Kratos)',
157 extension: '.mdpa',
158 blurb:
159 'Input format of the Kratos multiphysics framework. Geometry only — meshio writes ' +
160 'mesh data corruptly, so the app strips it to keep the file valid.',
161 capabilities: { normals: false, colors: false },
162 },
163 {
164 id: 'tecplot',
165 label: 'Tecplot',
166 extension: '.dat',
167 blurb:
168 'Tecplot ASCII data format. Normals and colors travel as per-node variables ' +
169 '(nx/ny/nz, red/green/blue).',
170 capabilities: { normals: true, colors: true },
171 },
172 {
173 id: 'dolfin-xml',
174 label: 'DOLFIN XML',
175 extension: '.xml',
176 blurb: 'Legacy XML format of the FEniCS/DOLFIN project. Geometry only.',
177 capabilities: { normals: false, colors: false },
178 },
179 {
180 id: 'permas',
181 label: 'PERMAS',
182 extension: '.post',
183 blurb: 'PERMAS FEA text format. Geometry only.',
184 capabilities: { normals: false, colors: false },
185 },
188export function formatForFilename(filename: string): MeshFormat | null {
189 const lower = filename.toLowerCase()
190 return formats.find((f) => lower.endsWith(f.extension)) ?? null
193export const acceptedExtensions = formats.map((f) => f.extension)
195/**
196 * Human-readable list of attributes of `mesh` that `target` cannot store
197 * (empty array means the conversion is lossless).
198 */
199export function conversionLosses(mesh: MeshData, target: MeshFormat): string[] {
200 const losses: string[] = []
201 if (mesh.normals && !target.capabilities.normals) losses.push('vertex normals')
202 if (mesh.colors && !target.capabilities.colors) losses.push('vertex colors')
203 return losses
moveopenescclose