subagent transcript

session 17f09f89
delegated task
You are porting FreeCAD's FEM module to WebAssembly (emscripten). The `Fem` C++ module normally links against SMESH/SMDS/VTK (the salomesmesh mesher),
▸ Magik
You are porting FreeCAD's FEM module to WebAssembly (emscripten). The `Fem` C++ module normally links against SMESH/SMDS/VTK (the salomesmesh mesher), but in the wasm build NONE of those libraries exist. Your job: write a SELF-CONTAINED wasm stub implementation of the `Fem::FemMesh` class that compiles and links WITHOUT any SMESH/SMDS/VTK/Driver headers, so the FEM document `FEMExample.FCStd` can LOAD with mesh objects as empty shells (no geometry). Meshing/solving is out of scope — those never run in wasm. REPO: /home/magik6k/lcad-wasm/freecad-port/FreeCAD TARGET FILE TO WRITE: /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh_wasm.cpp STEP 1 — Read these to learn the EXACT interface and the real (non-SMESH) logic you must preserve: - src/Mod/Fem/App/FemMesh.h (the class declaration — I already added an __EMSCRIPTEN__ guard providing the SMDSAbs_ElementType enum and SMESH_VERSION_MAJOR=9; the members `SMESH_Mesh* myMesh`, `std::list<SMESH_HypothesisPtr> hypoth`, `static SMESH_Gen* _mesh_gen` remain as forward-declared-pointer members) - src/Mod/Fem/App/FemMesh.cpp (the REAL implementation — read it to replicate the NON-SMESH bodies of: the constructors, destructor, operator=, getPyObject, getMemSize, Save, Restore, SaveDocFile, RestoreDocFile, setTransform, getTransform. For everything SMESH-dependent you will stub.) - src/Mod/Fem/App/FemMeshProperty.cpp / .h (PropertyFemMesh — check whether IT or FemMesh registers the doc-file via reader.addFile/writer.addFile; you MUST preserve FemMesh::Save/Restore's file-registration behavior exactly so RestoreDocFile still gets invoked at load, OR confirm PropertyFemMesh handles it and FemMesh::Save/Restore do something trivial) STEP 2 — Write FemMesh_wasm.cpp implementing EVERY method declared in FemMesh.h. Rules: - Includes: ONLY "PreCompiled.h", "FemMesh.h", "FemMeshPy.h", and standard/Base/App FreeCAD headers actually needed (Base/Writer.h, Base/Reader.h, Base/Exception.h, App/ComplexGeoData.h, Base/Console.h, etc.). ABSOLUTELY NO includes of anything matching SMESH*, SMDS*, SMESHDS*, StdMeshers*, Driver*, <vtk*>, <med*>, <hdf5*>. If you're tempted to include one, stub instead. - Define the static member: `SMESH_Gen* FemMesh::_mesh_gen = nullptr;` (SMESH_Gen is an incomplete forward-declared type — a null pointer definition is fine; do NOT dereference or delete it). - Constructors: initialize `myMesh = nullptr;` and default-init `hypoth` and `_Mtrx`. Do NOT call SMESH generator / CreateMesh. Copy-ctor and operator= copy `_Mtrx` only (myMesh stays nullptr). Preserve the TYPESYSTEM_SOURCE macro call that the real FemMesh.cpp uses at top (check the real file for `TYPESYSTEM_SOURCE(Fem::FemMesh, ...)`). - Destructor: empty body. Do NOT `delete myMesh` (it's an incomplete type and always null). - getSMesh() const / non-const: return myMesh (nullptr). - getGenerator(): return nullptr. - getPyObject(): replicate the real one (returns `new FemMeshPy(new FemMesh(*this))` or similar — copy the real pattern exactly; FemMeshPy.h is safe to include). - getMemSize(): return 0. - Save(Base::Writer&) / Restore(Base::XMLReader&): replicate the real behavior EXCEPT any SMESH calls. The goal is that the document's file-restore mechanism is preserved: if the real Save calls `writer.addFile(fileName, this)` and Restore reads a filename attribute + registers it, you MUST keep that so RestoreDocFile is still called at load. Strip only the SMESH mesh-writing/reading; keep the FreeCAD file-registration plumbing. If the real Save/Restore are trivial and PropertyFemMesh does the registration, replicate them trivially. - SaveDocFile(Base::Writer&): no-op (write nothing) OR write an empty placeholder — must not crash. Add a comment that mesh content is dropped in wasm. - RestoreDocFile(Base::Reader&): no-op body (read nothing). The document loader's readFiles() resyncs to the next zip entry via getNextEntry() regardless of how much is read, and it explicitly ignores unreadable files, so a no-op is SAFE and leaves the mesh empty. Add a comment. - All const geometry/query accessors (getElementTypes, countSubElements, getSubElement, getPoints, getSurfaceNodes, getNodesBySolid/Face/Edge/Vertex, getElementNodes, getNodeElements, getFacesByFace, getEdgesByEdge, getVolumesByFace, getccxVolumesByFace, getEdgesOnly, getFacesOnly, getBoundBox, getVolume, getInfo): return EMPTY/DEFAULT values (empty containers, empty BoundBox3d, Base::Quantity(0), a zero-filled FemMeshInfo). DO NOT THROW — these may be touched by rendering/inspection and must degrade gracefully. getSubElement may return nullptr. - setTransform/getTransform: operate on `_Mtrx` (real trivial behavior — copy from real file). - transformGeometry: apply to _Mtrx only (or no-op); do not touch SMESH. - Mutating / IO / compute methods (compute, addHypothesis, setStandardHypotheses, addGroup, addGroupElements, removeGroup, renameGroup, read, readVTKWithGroups, write, writeABAQUS, writeVTK, writeVTKWithGroups, writeZ88, copyMeshData, readNastran, readNastran95, readZ88, readAbaqus): throw `Base::NotImplementedError("FemMesh: meshing/IO is not available in the WebAssembly build")`. These are NOT on the document-restore path. - The template `createHypothesis<T>` is defined inline in the header and instantiated only by FemMesh.cpp's compute path — since you don't call it, you don't need to instantiate it. But if the linker complains, note it in your report. STEP 3 — Verify your file has NO forbidden includes: run `grep -nE 'SMESH|SMDS|StdMeshers|Driver|<vtk|<med|hdf5' src/Mod/Fem/App/FemMesh_wasm.cpp` — it should return only matches inside comments or the forward-declared type names from FemMesh.h (which is fine). Fix any real includes. Report back: (1) confirm the file is written, (2) the exact list of methods you gave REAL bodies vs stubbed-throw vs empty-return, (3) whether PropertyFemMesh or FemMesh handles doc-file registration and how you preserved it, (4) any method whose signature was ambiguous o …
Fable
thinking
I need to examine the required files first to understand the interface and how the actual implementation works.
Fable
I'll start by reading the key files to understand the exact interface and real implementation.
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh.h"}
tool result
1	/***************************************************************************
2	 *   Copyright (c) 2009 Jürgen Riegel <juergen.riegel@web.de>              *
3	 *                                                                         *
4	 *   This file is part of the FreeCAD CAx development system.              *
5	 *                                                                         *
6	 *   This library is free software; you can redistribute it and/or         *
7	 *   modify it under the  …[truncated]
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh.cpp"}
tool result
<system-reminder>[Truncated: PARTIAL view — showing lines 1-1409 of 2782 total (41952 tokens, cap 25000). Call Read with offset=1410 limit=1409 for the next page, or Grep to find a specific section. Do NOT answer from this page alone if the answer may be further in the file.]</system-reminder>

1	/***************************************************************************
2	 *   Copyright (c) 2009 Jürgen Riegel <juergen.riegel@web.de>              *
3	 *                                            …[truncated]
Fable
thinking
I'm continuing through the FemMesh.cpp file to examine the remaining methods like Save, Restore, SaveDocFile, RestoreDocFile, and various getter methods for properties like bounding box, volume, and element information.
Fable
Let me find the specific methods I need to replicate exactly. Let me grep for their definitions and read the FemMeshProperty files.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App && grep -nE '^(void|unsigned|Base::|std::|Data::|struct|int|bool|FemMesh|const)[^;]*FemMesh::(Save|Restore|SaveDocFile|RestoreDocFile|getPyObject|getMemSize|getInf…
tool result
344:std::list<std::pair<int, int>> FemMesh::getVolumesByFace(const TopoDS_Face& face) const
796:std::set<int> FemMesh::getEdgesOnly() const
841:std::set<int> FemMesh::getFacesOnly() const
1324:void FemMesh::readNastran(const std::string& Filename)
1419:void FemMesh::readNastran95(const std::string& Filename)
1551:void FemMesh::readAbaqus(const std::string& FileName)
1591:void FemMesh::readZ88(const std::string& FileName)
1631:void FemMesh::read(const char* FileName)
1681:void FemMesh::readVTKWit  …[truncated]
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMeshProperty.cpp"}
tool result
1	/***************************************************************************
2	 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>              *
3	 *                                                                         *
4	 *   This file is part of the FreeCAD CAx development system.              *
5	 *                                                                         *
6	 *   This library is free software; you can redistribute it and/or         *
7	 *   modify it under the  …[truncated]
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMeshProperty.h"}
tool result
1	/***************************************************************************
2	 *   Copyright (c) 2008 Jürgen Riegel <juergen.riegel@web.de>              *
3	 *                                                                         *
4	 *   This file is part of the FreeCAD CAx development system.              *
5	 *                                                                         *
6	 *   This library is free software; you can redistribute it and/or         *
7	 *   modify it under the  …[truncated]
Fable
thinking
I need to examine the specific method implementations for the core geometry operations like Save, Restore, SaveDocFile, RestoreDocFile, and various property getters and setters across a large section of the code.
Fable
Now let me read the key method bodies I need to replicate exactly (Save/Restore/DocFile, transform, getInfo, getBoundBox, getVolume, getPyObject, getPoints, getElementTypes, etc.).
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh.cpp", "offset": 2325, "limit": 458}
tool result
2325	void FemMesh::write(const char* FileName) const
2326	{
2327	    Base::FileInfo File(FileName);
2328	
2329	    if (File.hasExtension("unv")) {
2330	        Base::Console().log("FEM mesh object will be exported to unv format.\n");
2331	        // write UNV file
2332	        myMesh->ExportUNV(File.filePath().c_str());
2333	    }
2334	    else if (File.hasExtension("med")) {
2335	        Base::Console().log("FEM mesh object will be exported to med format.\n");
2336	        myMesh->ExportMED(
23  …[truncated]
Fable
thinking
I'm looking for the getPyObject method in FemMesh.h and the grep results, but it's not showing up in either place. Let me check if it's inherited from the ComplexGeoData base class or if I need to search more broadly for where it's defined.
Fable
Let me check for getPyObject and verify the base class virtual methods, plus check how the file is currently built (CMakeLists) to understand what's expected.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App && echo \"=== getPyObject in FemMesh.cpp ===\" && grep -n \"getPyObject\" FemMesh.cpp; echo \"=== getPyObject in FemMesh.h ===\" && grep -n \"getPyObject\" FemMesh…
tool result
=== getPyObject in FemMesh.cpp ===
=== getPyObject in FemMesh.h ===
=== ComplexGeoData getPyObject decl ===
=== readZ88/readAbaqus/read/readVTK signatures ===
1:void FemMesh::readZ88(const std::string& FileName)
4:    Base::Console().log("Start: FemMesh::readZ88() =================================\n");
32:            throw Base::FileException("Problems reading file");
41:void FemMesh::read(const char* FileName)
48:        throw Base::FileException("File to load not existing or not readable", Fil  …[truncated]
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App && echo \"=== CMake references to FemMesh_wasm or FemMesh.cpp ===\" && grep -rn \"FemMesh_wasm\\|FemMesh.cpp\\|EMSCRIPTEN\\|WASM\" CMakeLists.txt 2>/dev/null | hea…
tool result
=== CMake references to FemMesh_wasm or FemMesh.cpp ===
CMakeLists.txt:121:    FemMesh.cpp
zshexit:1: parameter HISTDB_FD does not contain a file descriptor
Fable
thinking
I'm realizing that `getPyObject` isn't defined in FemMesh.h or FemMesh.cpp, so it must be inherited from the base class `Data::ComplexGeoData`. But the task explicitly asks me to implement it, so I need to figure out where it's actually defined and how to replicate it for FemMesh. I need to search more systematically across the codebase to confirm whether getPyObject is actually declared somewhere in the inheritance chain, since the task explicitly mentions it but I haven't found it yet in FemMesh.h or its immediate base classes.
Fable
getPyObject is not declared in FemMesh.h nor implemented in FemMesh.cpp. Let me verify the base-class hierarchy to confirm whether I must implement it, and read the remaining stub-throw methods' signatures precisely.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src && echo \"=== getPyObject anywhere in Mod/Fem/App ===\" && grep -rn \"getPyObject\" Mod/Fem/App/ | head; echo \"=== ComplexGeoData base + getPyObject/pure virtual ===\"; grep …
tool result
=== getPyObject anywhere in Mod/Fem/App ===
Mod/Fem/App/FemMeshShapeObject.cpp:95:PyObject* Fem::FemMeshShapeBaseObjectPython::getPyObject()
Mod/Fem/App/FemSetElementNodesObject.cpp:47:PyObject* FemSetElementNodesObject::getPyObject()
Mod/Fem/App/FemMeshShapeObject.h:67:    // virtual PyObject *getPyObject(void);
Mod/Fem/App/PropertyPostDataObject.h:62:    PyObject* getPyObject() override;
Mod/Fem/App/FemSetElementNodesObject.h:54:    PyObject* getPyObject() override;
Mod/Fem/App/FemConstraint.c  …[truncated]
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh.cpp", "offset": 1631, "limit": 100}
tool result
1631	void FemMesh::read(const char* FileName)
1632	{
1633	    Base::FileInfo File(FileName);
1634	    _Mtrx = Base::Matrix4D();
1635	
1636	    // checking on the file
1637	    if (!File.isReadable()) {
1638	        throw Base::FileException("File to load not existing or not readable", File);
1639	    }
1640	
1641	    if (File.hasExtension("unv")) {
1642	        // read UNV file
1643	        myMesh->UNVToMesh(File.filePath().c_str());
1644	    }
1645	    else if (File.hasExtension("med")) {
1646	  …[truncated]
Fable
thinking
I see that `getPyObject` isn't actually declared or implemented in FemMesh itself—the Python wrapping happens through FemMeshPy and PropertyFemMesh instead. So I won't be defining it in FemMesh, which avoids creating a duplicate symbol.

The `SMDSAbs_ElementType` enum used in getNodeElements is already provided in the header for wasm, so that's covered. For the doc-file registration, FemMesh::Save writes the file attribute and calls `writer.addFile("FemMesh.unv", this)` to register itself for SaveDocFile, while Restore reads the file attribute and calls `reader.addFile` to trigger RestoreDocFile later. PropertyFemMesh just delegates to FemMesh for all of this. When loading an existing FemExa  …
Fable
I now have the full picture. Let me verify `Base::NotImplementedError` exists and confirm `Base::Unit::Volume`.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src && echo \"=== NotImplementedError ===\" && grep -rn \"class BaseExport NotImplementedError\\|NotImplementedError\" Base/Exception.h | head; echo \"=== Unit::Volume ===\" && gr…
tool result
=== NotImplementedError ===
Base/Exception.h:413:class BaseExport NotImplementedError: public Exception
Base/Exception.h:416:    explicit NotImplementedError(const std::string& message = "Not implemented error");
=== Unit::Volume ===
Base/Unit.h:143:    static const Unit InverseVolume;
Base/Unit.h:171:    static const Unit Volume;
Base/Unit.h:172:    static const Unit VolumeChargeDensity;
Base/Unit.h:173:    static const Unit VolumeFlowRate;
Base/Unit.h:174:    static const Unit VolumetricTher  …[truncated]
Fable
thinking
I've confirmed the necessary classes and exceptions exist, so now I'm setting up the file with the required headers—PreCompiled.h, FemMesh.h, Base/Writer.h for stream operations and file management, and Base/Reader.h for XML parsing functions.

I also need Base/Exception.h for NotImplementedError, Base/Matrix.h for the 4D matrix type that comes through ComplexGeoData, Base/BoundBox.h for the bounding box, and Base/Unit.h for the volume unit. I don't need App/Application.h since my stub implementations won't use getTempFileName, and I'm skipping FemMeshPy.h since there's no getPyObject method to handle.

Now I'm setting up the TYPESYSTEM_SOURCE macro... Now I'm reviewing the method signatures  …
Fable
All confirmed. `getPyObject` is NOT a `FemMesh` member (it's not declared in `FemMesh.h` nor defined in `FemMesh.cpp`), so I must not define it. `Base::NotImplementedError` and `Base::Unit::Volume` both exist. `Save`/`Restore` contain no SMESH calls (pure file-registration + matrix I/O), so they copy verbatim. Now writing the file.
Fable
⚙ Write {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh_wasm.cpp", "content": "/***************************************************************************\n * Copyright (c) 2009 Jürgen Riegel <juergen.riegel@w…
tool result
File created successfully at: /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh_wasm.cpp (file state is current in your context — no need to Read it back)
Fable
Now let me verify there are no forbidden includes and do a sanity check on the method coverage.
Fable
⚙ Bash {"command": "echo \"=== forbidden-token grep (STEP 3) ===\" && grep -nE 'SMESH|SMDS|StdMeshers|Driver|<vtk|<med|hdf5' src/Mod/Fem/App/FemMesh_wasm.cpp; echo \"--- exit: $? (1 = no matches outside expected) ---\"; echo; echo \"=== #include l…
tool result
=== forbidden-token grep (STEP 3) ===
27:// SMESH / SMDS / SMESHDS / StdMeshers / Driver / VTK / MED / HDF5. NONE of
39:// operation that would need SMESH throws Base::NotImplementedError. Read-only
43:// IMPORTANT: this file must NOT include anything from SMESH/SMDS/SMESHDS/
44:// StdMeshers/Driver/VTK/MED/HDF5. The pointer members (myMesh, _mesh_gen) are
72:// SMESH_Gen is an incomplete forward-declared type in the wasm build; a null
74:SMESH_Gen* FemMesh::_mesh_gen = nullptr;
91:// No SMESH g  …[truncated]
Fable
thinking
The forbidden-token matches are all contained within comments or forward-declared type names that come from FemMesh.h, so they're acceptable. I'm verifying that there are no actual `#include` directives pulling in forbidden headers—everything is coming from PreCompiled.h, standard library headers, or FreeCAD's Base/App modules. Now I need to cross-check the header against the declared methods to make sure I haven't missed anything. Continuing through the remaining methods and verifying the implementation details — all 55 methods are accounted for, including the static getGenerator() and the noreturn helper function that prevents compiler warnings in methods with non-void returns. The aggrega  …
Fable
All forbidden-token matches are inside comments or the forward-declared type names from `FemMesh.h` (`SMESH_Gen`, `SMESH_Mesh`, `SMESH_HypothesisPtr`, `SMDSAbs_ElementType`) — none are includes. Let me confirm the include paths exist and that CMake picks the wasm TU.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src && for h in Base/BoundBox.h Base/Matrix.h Base/Quantity.h Base/Reader.h Base/Unit.h Base/Writer.h Base/Exception.h App/ComplexGeoData.h Mod/Fem/App/PreCompiled.h; do [ -f \"$h…
tool result
OK  Base/BoundBox.h
OK  Base/Matrix.h
OK  Base/Quantity.h
OK  Base/Reader.h
OK  Base/Unit.h
OK  Base/Writer.h
OK  Base/Exception.h
OK  App/ComplexGeoData.h
OK  Mod/Fem/App/PreCompiled.h

=== how CMake selects FemMesh source (wasm swap) ===
22:# wasm: SMESH/SMDS/VTK are not built (no VTK/MED/HDF5). FemMesh is stubbed
23:# (FemMesh_wasm.cpp) so the module loads FEM documents with empty-shell meshes.
24:if (NOT EMSCRIPTEN)
40:if (EMSCRIPTEN)
41:    # wasm: keep the .pyi (drives FemMeshPy.h/.cpp gen  …[truncated]
Fable
thinking
The CMake configuration already handles the EMSCRIPTEN swap between FemMesh.cpp and FemMesh_wasm.cpp, and all the necessary headers are in place, so my implementation is complete. I'm also noting that the Python wrapper layer is handled separately through FemMeshPyImp_wasm.cpp, which confirms the architecture is sound.

I've verified there are no other exported symbols or free functions in FemMesh.cpp that would be missing from my implementation—just the FemMesh class methods and internal anonymous-namespace classes. The method signatures match the header declarations exactly, including default parameters like the SMDSAbs_ElementType enum and the float Angle parameter. Everything checks out,  …
Fable
Everything checks out. The CMake already swaps `FemMesh.cpp` → `FemMesh_wasm.cpp` under EMSCRIPTEN (lines 149–152), all include headers resolve, and the Python wrapper is handled separately by `FemMeshPyImp_wasm.cpp`. ## Report **(1) File written:** `/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/Fem/App/FemMesh_wasm.cpp` — self-contained, no SMESH/SMDS/StdMeshers/Driver/VTK/MED/HDF5 includes. The forbidden-token grep matches only comments and the forward-declared type names from `FemMesh.h` (`SMESH_Gen`, `SMESH_Mesh`, `SMESH_HypothesisPtr`, `SMDSAbs_ElementType`), never `#include` lines. Includes are only PreCompiled.h, std headers, `App/ComplexGeoData.h`, and `Base/{BoundBox,Matrix,Quantity,Reader,Unit,Writer,Exception}.h`. All 8 Base/App headers verified present. Static member `SMESH_Gen* FemMesh::_mesh_gen = nullptr;` and `TYPESYSTEM_SOURCE(Fem::FemMesh, Base::Persistence)` replicated. **(2) Method classification** (all 54 non-template declared methods defined; `createHypothesis<T>` is header-inline and left uninstantiated): - **REAL bodies (preserve exact desktop logic, no SMESH):** - Constructors (`myMesh=nullptr`, default `_Mtrx`), copy-ctor/`operator=` (copy `_Mtrx` only), destructor (empty — no `delete`) - `getSMesh() const/non-const` → `myMesh` (null); `getGenerator()` → `nullptr`; `getMemSize()` → 0 - `Save` and `Restore` — copied **verbatim** (they contain zero SMESH calls; pure `addFile`/matrix I/O) - `getElementTypes` (static Vertex/Edge/Face/Volume list), `getSubElement`→nullptr, `countSubElements`→0 - `setTransform`/`getTransform` (operate on `_Mtrx`) - **EMPTY / default-return (never throw — safe for render/inspection):** `getSurfaceNodes`, `getNodesBySolid/Face/Edge/Vertex`, `getElementNodes`, `getNodeElements`, `getFacesByFace`, `getEdgesByEdge`, `getVolumesByFace`, `getccxVolumesByFace`, `getEdgesOnly`, `getFacesOnly`, `getPoints` (clears both vectors), `getBoundBox` (empty `BoundBox3d`), `getVolume` (`Base::Quantity(0.0, Base::Unit::Volume)`), `getInfo` (zero-filled `FemMeshInfo`), `transformGeometry` (no-op — no nodes), `SaveDocFile` (writes nothing), `RestoreDocFile` (reads nothing) - **THROW `Base::NotImplementedError`** (via a shared `[[noreturn]]` helper; not on the restore path): `addHypothesis`, `setStandardHypotheses`, `compute`, `addGroup`, `addGroupElements`, `removeGroup`, `renameGroup`, `read`, `readVTKWithGroups`, `write`, `writeABAQUS`, `writeVTK`, `writeVTKWithGroups`, `writeZ88`, `copyMeshData`, `readNastran`, `readNastran95`, `readZ88`, `readAbaqus` **(3) Doc-file registration — FemMesh handles it, and it's preserved.** `PropertyFemMesh::{Save,Restore,SaveDocFile,RestoreDocFile}` merely forward to the owned `FemMesh`. `FemMesh::Save` calls `writer.addFile("FemMesh.unv", this)` and `FemMesh::Restore` reads the `file` attribute and calls `reader.addFile(file.c_str(), this)`. I kept both **byte-for-byte identical** to the desktop build, so at load the reader still schedules and invokes `RestoreDocFile` on this object — which is now a no-op, leaving an empty mesh. Only the SMESH payload previously written/read inside `SaveDocFile`/`RestoreDocFile` (`ExportUNV`/`UNVToMesh`) was dropped. **(4) Signature/linker notes:** - **`getPyObject` is NOT a FemMesh member** — it is not declared in `FemMesh.h` nor defined in the real `FemMesh.cpp` (verified), and `Data::ComplexGeoData` does not declare it. The Python object is produced by `PropertyFemMesh::getPyObject` / `FemMeshPy` separately. So, contrary to the task note, I deliberately did **not** define `FemMesh::getPyObject` (doing so would be an error — no such member) and did not include `FemMeshPy.h`. - **`createHypothesis<T>` template:** header-inline, ODR-used only by the real `setStandardHypotheses` (which here throws and never instantiates it). No instantiation occurs, so no linker risk. If a future TU references it, it would pull in `StdMeshers_*` — none does in the FEM base lib. - **`_mesh_gen`:** defined as a null pointer of the incomplete `SMESH_Gen*`; never dereferenced/deleted — safe. - The `[[noreturn]]` helper lets the `int`/`bool`-returning throwers (`addGroup`, `removeGroup`) compile without a return statement. - Because `SMESH_VERSION_MAJOR` is defined as 9 in the header's `__EMSCRIPTEN__` branch, the `myStudyId` member does not exist, so constructors correctly omit it. CMake already performs the swap (`list(REMOVE_ITEM ... FemMesh.cpp)` / `list(APPEND ... FemMesh_wasm.cpp)` under `EMSCRIPTEN`), so no build-file edits were needed. Per instructions, no other files were modified and no build was run.