engine, ui: mesh.node.relax and relaxation fields, Relax Nodes tool with sphere and preview (#398)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-15 14:40:00 -04:00
1 parent 75f9e5ae6e
commit 94fdbf0fca
19 files changed
+1038 -9

No files matched your search

+2 -1
View File
@@ -6,7 +6,7 @@ Every entry is a toolbar button. **Ready** entries run their command; **coming s
shown greyed with the roadmap milestone that brings them (ROADMAP.md). Scripts, the command line,
the control channel and AI agents over MCP (docs/mcp.md) run the same commands.
70 ready, 39 coming soon.
71 ready, 39 coming soon.
## Geometry
@@ -50,6 +50,7 @@ the control channel and AI agents over MCP (docs/mcp.md) run the same commands.
| Edit | Element — Add an element on existing nodes | ready | `mesh.element.add`, `mesh.element.remove`, `mesh.clear` |
| Edit | Mirror Mesh — Mirror a body's mesh across a plane, joined on the plane (mesh half a symmetric part) | ready | `mesh.mirror` |
| Edit | Merge Nodes — Merge coincident nodes, keeping sets, loads and boundary conditions on the survivors; check for duplicates and cracks, renumber | ready | `mesh.node.merge`, `mesh.check.duplicates`, `mesh.renumber` |
| Improve | Relax Nodes — Relax the nodes inside a sphere to fix spikes and slivers; surface nodes slide on the geometry; kept as a field to apply again after a remesh | ready | `mesh.node.relax`, `mesh.node.relax.apply` |
| Edit | Remesh Region — Remesh a region in place; split and collapse elements | coming soon (M6) | |
| Edit | Orphan Mesh — Import a mesh without geometry | coming soon (M6) | |
| Verify | Quality — Quality metrics and the certified validity check, failing elements listed | ready | `mesh.quality` |
+18
View File
@@ -167,6 +167,24 @@ edges of partition cells matching counts.
4. `mesh.seed.list` lists the seeds and the edges they reach (`stale` when the design has no such
edge); `mesh.seed.clear {edges?}` removes them. Seeds are saved with the model.
## Relaxing a few bad elements
When `mesh.quality` shows a handful of spikes in an otherwise good mesh:
1. `execute` `mesh.node.relax {"around_element": <the scaled Jacobian's worst>}` (or `{"center":
[x, y, z], "radius": r}`, or `nodes` / `elements` / `set`; `iterations`, `strength`, `falloff`).
Nodes there relax (smart Laplacian, then optimization of the worst element), each move kept
only when the worst element around the node does not get worse and nothing inverts. Nodes on a
B-rep face slide in its UV parameters and stay on it, nodes on a B-rep edge slide along it,
vertex nodes stay; nodes on a partition cut face move freely (both cells share them). The
reply gives the nodes moved, the largest displacement, and the region's smallest scaled
Jacobian, largest edge ratio and worst elements before and after. One undo step.
2. The relaxation is kept as a field of the model (`field`, default `Relax1`, …; saved with it).
After a remesh, `mesh.node.relax.apply {"field": "Relax1"}` puts the relaxed shape on the new
mesh (each node takes the displacement interpolated in the old cell it lies in, on its face,
then one guarded smoothing sweep); with `"reapply": true` on the relaxation every remesh does
it by itself (the mesher's reply lists `relaxations_applied`).
## Limits
The server treats its input as hostile. A message line may be at most 16 MiB (the control
+19
View File
@@ -952,6 +952,25 @@ input points), Steiner points kept half the local spacing from the boundary.
is exact: a planar bilinear quad's Jacobian is affine in each reference coordinate, so four exact `orient2d` corner
tests decide it.
### B7a. Node relaxation of a finished mesh (implemented in `fieldcraft-mesh::relax`, `mesh.node.relax`)
- **Method.** Smart Laplacian (S. Canann, J. Tristano, M. Staten, *An approach to combined Laplacian and
optimization-based smoothing for triangular, quadrilateral, and quad-dominant meshes*, IMR 1998; L. Freitag 1997
above): a node's weighted step toward the centroid of its edge neighbours is kept only when the worst element
around it does not get worse and no element inverts, halved otherwise. Then one step up the gradient of the worst
element's quality (the active max–min element of Freitag and Ollivier-Gooch, IJNME 40, 1997; P. Knupp, IJNME 48,
2000), kept only when it raises the worst. Quality is the scaled Jacobian of `crate::quality`; validity its
certified check.
- **Surface nodes in UV.** A node on a B-rep face moves in the face's own parameters (the displacement resolved on
the surface's coordinate directions, then the surface evaluated there), so it stays exactly on an analytic face;
free-form faces fall back to projection onto the face's tessellation (SolidCraft's kernel exposes the analytic
surfaces only). Nodes on a B-rep edge slide along it; vertex nodes are held; partition cut faces are not
geometry, so their nodes move freely.
- **Relaxation fields.** What a relaxation did is kept as the relaxed region's cells before and after; a later
mesh takes the displacement at each node's parametric coordinates in the old cell holding it (barycentric or
trilinear shape functions), slides it onto its face or edge, undoes any move that would invert an element, and
smooths once (`mesh.node.relax.apply`, or `reapply` after every remesh).
---
### B8. Mapped and swept hexahedral meshing (implemented in `fieldcraft-mesh::hex`)