feat(P3): add GMSH Frontal-Delaunay tessellation engine
Introduces GMSH as an alternative to OCC BRepMesh for STEP→GLB tessellation. GMSH produces conforming meshes that eliminate fan triangles at cylinder seam edges — a structural limitation of OCC BRepMesh that cannot be fixed via deflection parameters. Changes: - render-worker/Dockerfile: install gmsh>=4.15.0 + libglu1-mesa + libxft2 - export_step_to_gltf.py: --tessellation_engine occ|gmsh CLI arg + _tessellate_with_gmsh() using BRep→GMSH→Poly_Triangulation write-back - admin.py: tessellation_engine setting (SETTINGS_DEFAULTS, SettingsOut, SettingsUpdate, validation) - export_glb.py: pass tessellation_engine to export_step_to_gltf.py CLI in both geometry and production GLB tasks - Admin.tsx: radio button UI for OCC vs GMSH selection Tested: 121 faces meshed, 0 BRepMesh fallback, 649K triangles on sample part. Clean seam edges for UV unwrap — GMSH respects B-rep periodic face boundaries. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,8 @@ SETTINGS_DEFAULTS: dict[str, str] = {
|
||||
"smtp_user": "",
|
||||
"smtp_password": "",
|
||||
"smtp_from_address": "",
|
||||
# glTF tessellation quality (OCC BRepMesh)
|
||||
# glTF tessellation quality
|
||||
"tessellation_engine": "occ", # "occ" | "gmsh" — tessellation backend
|
||||
"gltf_preview_linear_deflection": "0.1", # mm — geometry GLB for viewer
|
||||
"gltf_preview_angular_deflection": "0.1", # rad — Standard preset
|
||||
"gltf_production_linear_deflection": "0.03", # mm — production GLB
|
||||
@@ -87,6 +88,7 @@ class SettingsOut(BaseModel):
|
||||
gltf_material_quality: str = "pbr_colors"
|
||||
gltf_pbr_roughness: float = 0.4
|
||||
gltf_pbr_metallic: float = 0.6
|
||||
tessellation_engine: str = "occ"
|
||||
|
||||
|
||||
class SettingsUpdate(BaseModel):
|
||||
@@ -119,6 +121,7 @@ class SettingsUpdate(BaseModel):
|
||||
gltf_material_quality: str | None = None
|
||||
gltf_pbr_roughness: float | None = None
|
||||
gltf_pbr_metallic: float | None = None
|
||||
tessellation_engine: str | None = None
|
||||
|
||||
|
||||
@router.get("/users", response_model=list[UserOut])
|
||||
@@ -237,6 +240,7 @@ def _settings_to_out(raw: dict[str, str]) -> SettingsOut:
|
||||
gltf_material_quality=raw.get("gltf_material_quality", "pbr_colors"),
|
||||
gltf_pbr_roughness=float(raw.get("gltf_pbr_roughness", "0.4")),
|
||||
gltf_pbr_metallic=float(raw.get("gltf_pbr_metallic", "0.6")),
|
||||
tessellation_engine=raw.get("tessellation_engine", "occ"),
|
||||
)
|
||||
|
||||
|
||||
@@ -361,6 +365,10 @@ async def update_settings(
|
||||
if not (0.05 <= body.gltf_production_angular_deflection <= 1.5):
|
||||
raise HTTPException(400, detail="gltf_production_angular_deflection must be 0.05–1.5 rad")
|
||||
updates["gltf_production_angular_deflection"] = str(body.gltf_production_angular_deflection)
|
||||
if body.tessellation_engine is not None:
|
||||
if body.tessellation_engine not in {"occ", "gmsh"}:
|
||||
raise HTTPException(400, detail="tessellation_engine must be 'occ' or 'gmsh'")
|
||||
updates["tessellation_engine"] = body.tessellation_engine
|
||||
|
||||
for k, v in updates.items():
|
||||
await _save_setting(db, k, v)
|
||||
|
||||
Reference in New Issue
Block a user