Эх сурвалжийг харах

Adding mesh_to_step script

Nicole Portas 2 сар өмнө
parent
commit
15476b1570
1 өөрчлөгдсөн 122 нэмэгдсэн , 0 устгасан
  1. 122 0
      mesh_to_step.py

+ 122 - 0
mesh_to_step.py

@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+"""
+=============================================================================
+STL Mesh to Parametric STEP Solid Converter (OpenCASCADE Backend)
+=============================================================================
+Requirements (Run inside your environment before executing):
+    pip install trimesh scipy cadquery
+
+Usage:
+    python mesh_to_step.py <path_to_mesh.stl>
+=============================================================================
+"""
+
+import sys
+from pathlib import Path
+
+try:
+    import trimesh
+    import cadquery as cq
+    from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeFace, BRepBuilderAPI_Sewing, BRepBuilderAPI_MakeSolid, BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire
+    from OCP.gp import gp_Pnt
+except ImportError as e:
+    print(f"[fucking error] Missing dependencies. Run: pip install trimesh scipy cadquery")
+    print(f"Details: {e}")
+    sys.exit(1)
+
+def mesh_to_step(input_path):
+    input_file = Path(input_path)
+    if not input_file.exists():
+        print(f"[fucking error] File not found: {input_file}")
+        sys.exit(1)
+        
+    output_step = input_file.with_suffix('.step')
+    
+    print(f"[*] Loading mesh: {input_file}")
+    mesh = trimesh.load(input_file, force='mesh')
+    
+    print("[*] Running geometry healing filters...")
+    mesh.update_faces(mesh.unique_faces())
+    mesh.fill_holes()
+    
+    print(f"[*] Extracting {len(mesh.faces)} facets and building faces...")
+    # 0.1mm tolerance to sew loose vertices and fix misaligned triangle normals
+    sewing = BRepBuilderAPI_Sewing(0.1)
+    
+    success_faces = 0
+    for face in mesh.faces:
+        p1 = gp_Pnt(float(mesh.vertices[face[0]][0]), float(mesh.vertices[face[0]][1]), float(mesh.vertices[face[0]][2]))
+        p2 = gp_Pnt(float(mesh.vertices[face[1]][0]), float(mesh.vertices[face[1]][1]), float(mesh.vertices[face[1]][2]))
+        p3 = gp_Pnt(float(mesh.vertices[face[2]][0]), float(mesh.vertices[face[2]][1]), float(mesh.vertices[face[2]][2]))
+        
+        try:
+            ocp_face = BRepBuilderAPI_MakeFace(p1, p2, p3).Face()
+            sewing.Add(ocp_face)
+            success_faces += 1
+        except Exception:
+            try:
+                # Fallback path if raw surface generation hits a localized coordinate breakdown
+                e1 = BRepBuilderAPI_MakeEdge(p1, p2).Edge()
+                e2 = BRepBuilderAPI_MakeEdge(p2, p3).Edge()
+                e3 = BRepBuilderAPI_MakeEdge(p3, p1).Edge()
+                wire = BRepBuilderAPI_MakeWire(e1, e2, e3).Wire()
+                ocp_face = BRepBuilderAPI_MakeFace(wire).Face()
+                sewing.Add(ocp_face)
+                success_faces += 1
+            except Exception:
+                continue
+
+    print(f"[*] Successfully added {success_faces}/{len(mesh.faces)} faces to the engine.")
+    if success_faces == 0:
+        print("[fucking error] All faces rejected by OpenCASCADE geometry constraints.")
+        sys.exit(1)
+
+    print("[*] Sewing facets together via OpenCASCADE engine...")
+    sewing.Perform()
+    
+    print("\n=== OpenCASCADE Sewing Diagnostics ===")
+    print(f"Free edges (gaps): {sewing.NbFreeEdges()}")
+    print(f"Multiple edges: {sewing.NbMultipleEdges()}")
+    print("======================================\n")
+
+    sewed_shape = sewing.SewedShape()
+    
+    print("[*] Computing solid volume...")
+    solid_builder = BRepBuilderAPI_MakeSolid()
+    
+    from OCP.TopExp import TopExp_Explorer
+    from OCP.TopAbs import TopAbs_SHELL
+    from OCP.TopoDS import TopoDS
+    
+    explorer = TopExp_Explorer(sewed_shape, TopAbs_SHELL)
+    shell_count = 0
+    
+    while explorer.More():
+        shell = TopoDS.Shell(explorer.Current())
+        solid_builder.Add(shell)
+        shell_count += 1
+        explorer.Next()
+        
+    if shell_count == 0:
+        print("[fucking error] Sewing failed to produce a valid shell structure.")
+        sys.exit(1)
+        
+    if not solid_builder.IsDone():
+        print("[fucking error] OpenCASCADE sewed the shell but cannot compute a closed solid volume.")
+        sys.exit(1)
+        
+    ocp_solid = solid_builder.Solid()
+    
+    # Cast directly into CadQuery's core Shape object to handle pristine STEP output
+    cq_shape = cq.Shape.cast(ocp_solid)
+    
+    print(f"[*] Exporting pristine STEP file: {output_step}")
+    cq.exporters.export(cq_shape, str(output_step), cq.exporters.ExportTypes.STEP)
+    print("[+] Done!")
+
+if __name__ == "__main__":
+    if len(sys.argv) < 2:
+        print("Usage: python mesh_to_step.py <path_to_mesh.stl>")
+        sys.exit(1)
+        
+    mesh_to_step(sys.argv[1])