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:
@@ -112,6 +112,7 @@ export default function AdminPage() {
|
||||
gltf_preview_angular_deflection: number
|
||||
gltf_production_linear_deflection: number
|
||||
gltf_production_angular_deflection: number
|
||||
tessellation_engine: string
|
||||
}
|
||||
|
||||
const { data: settings } = useQuery({
|
||||
@@ -1459,6 +1460,34 @@ export default function AdminPage() {
|
||||
)
|
||||
})()}
|
||||
|
||||
{/* Tessellation engine selector */}
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs font-semibold text-content-secondary uppercase tracking-wide">Tessellation Engine</p>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
{[
|
||||
{ value: 'occ', label: 'OCC BRepMesh', description: 'Default engine. Fast, but produces fan triangles at cylinder seam edges.' },
|
||||
{ value: 'gmsh', label: 'GMSH Frontal-Delaunay', description: 'Conforming mesh — no fan triangles on cylinders. +10–30% export time. Recommended for cylindrical parts.' },
|
||||
].map(opt => (
|
||||
<label key={opt.value} className="flex items-start gap-3 cursor-pointer p-3 rounded-lg border border-border-default hover:border-blue-400 transition-colors">
|
||||
<input
|
||||
type="radio"
|
||||
name="tessellation_engine"
|
||||
value={opt.value}
|
||||
checked={(tess.tessellation_engine ?? 'occ') === opt.value}
|
||||
onChange={() => setTessellationDraft(d => ({ ...d, tessellation_engine: opt.value }))}
|
||||
className="mt-0.5 shrink-0"
|
||||
/>
|
||||
<div>
|
||||
<div className="text-sm font-medium">{opt.label}</div>
|
||||
<div className="text-xs text-content-muted mt-0.5">{opt.description}</div>
|
||||
</div>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Manual inputs */}
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user